• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2008, http://www.snakeyaml.org
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.yaml.snakeyaml;
17 
18 import java.io.IOException;
19 import java.io.InputStream;
20 import java.io.Reader;
21 import java.io.StringReader;
22 import java.io.StringWriter;
23 import java.io.Writer;
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.regex.Pattern;
28 
29 import org.yaml.snakeyaml.DumperOptions.FlowStyle;
30 import org.yaml.snakeyaml.composer.Composer;
31 import org.yaml.snakeyaml.constructor.BaseConstructor;
32 import org.yaml.snakeyaml.constructor.Constructor;
33 import org.yaml.snakeyaml.emitter.Emitable;
34 import org.yaml.snakeyaml.emitter.Emitter;
35 import org.yaml.snakeyaml.error.YAMLException;
36 import org.yaml.snakeyaml.events.Event;
37 import org.yaml.snakeyaml.introspector.BeanAccess;
38 import org.yaml.snakeyaml.nodes.Node;
39 import org.yaml.snakeyaml.nodes.Tag;
40 import org.yaml.snakeyaml.parser.Parser;
41 import org.yaml.snakeyaml.parser.ParserImpl;
42 import org.yaml.snakeyaml.reader.StreamReader;
43 import org.yaml.snakeyaml.reader.UnicodeReader;
44 import org.yaml.snakeyaml.representer.Representer;
45 import org.yaml.snakeyaml.resolver.Resolver;
46 import org.yaml.snakeyaml.serializer.Serializer;
47 
48 /**
49  * Public YAML interface. Each Thread must have its own instance.
50  */
51 public class Yaml {
52     protected final Resolver resolver;
53     private String name;
54     protected BaseConstructor constructor;
55     protected Representer representer;
56     protected DumperOptions dumperOptions;
57 
58     /**
59      * Create Yaml instance. It is safe to create a few instances and use them
60      * in different Threads.
61      */
Yaml()62     public Yaml() {
63         this(new Constructor(), new Representer(), new DumperOptions(), new Resolver());
64     }
65 
66     /**
67      * Create Yaml instance.
68      *
69      * @param dumperOptions
70      *            DumperOptions to configure outgoing objects
71      */
Yaml(DumperOptions dumperOptions)72     public Yaml(DumperOptions dumperOptions) {
73         this(new Constructor(), new Representer(), dumperOptions);
74     }
75 
76     /**
77      * Create Yaml instance. It is safe to create a few instances and use them
78      * in different Threads.
79      *
80      * @param representer
81      *            Representer to emit outgoing objects
82      */
Yaml(Representer representer)83     public Yaml(Representer representer) {
84         this(new Constructor(), representer);
85     }
86 
87     /**
88      * Create Yaml instance. It is safe to create a few instances and use them
89      * in different Threads.
90      *
91      * @param constructor
92      *            BaseConstructor to construct incoming documents
93      */
Yaml(BaseConstructor constructor)94     public Yaml(BaseConstructor constructor) {
95         this(constructor, new Representer());
96     }
97 
98     /**
99      * Create Yaml instance. It is safe to create a few instances and use them
100      * in different Threads.
101      *
102      * @param constructor
103      *            BaseConstructor to construct incoming documents
104      * @param representer
105      *            Representer to emit outgoing objects
106      */
Yaml(BaseConstructor constructor, Representer representer)107     public Yaml(BaseConstructor constructor, Representer representer) {
108         this(constructor, representer, new DumperOptions());
109     }
110 
111     /**
112      * Create Yaml instance. It is safe to create a few instances and use them
113      * in different Threads.
114      *
115      * @param representer
116      *            Representer to emit outgoing objects
117      * @param dumperOptions
118      *            DumperOptions to configure outgoing objects
119      */
Yaml(Representer representer, DumperOptions dumperOptions)120     public Yaml(Representer representer, DumperOptions dumperOptions) {
121         this(new Constructor(), representer, dumperOptions, new Resolver());
122     }
123 
124     /**
125      * Create Yaml instance. It is safe to create a few instances and use them
126      * in different Threads.
127      *
128      * @param constructor
129      *            BaseConstructor to construct incoming documents
130      * @param representer
131      *            Representer to emit outgoing objects
132      * @param dumperOptions
133      *            DumperOptions to configure outgoing objects
134      */
Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions)135     public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) {
136         this(constructor, representer, dumperOptions, new Resolver());
137     }
138 
139     /**
140      * Create Yaml instance. It is safe to create a few instances and use them
141      * in different Threads.
142      *
143      * @param constructor
144      *            BaseConstructor to construct incoming documents
145      * @param representer
146      *            Representer to emit outgoing objects
147      * @param dumperOptions
148      *            DumperOptions to configure outgoing objects
149      * @param resolver
150      *            Resolver to detect implicit type
151      */
Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions, Resolver resolver)152     public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions,
153             Resolver resolver) {
154         if (!constructor.isExplicitPropertyUtils()) {
155             constructor.setPropertyUtils(representer.getPropertyUtils());
156         } else if (!representer.isExplicitPropertyUtils()) {
157             representer.setPropertyUtils(constructor.getPropertyUtils());
158         }
159         this.constructor = constructor;
160         representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle());
161         representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle());
162         representer.getPropertyUtils().setAllowReadOnlyProperties(
163                 dumperOptions.isAllowReadOnlyProperties());
164         representer.setTimeZone(dumperOptions.getTimeZone());
165         this.representer = representer;
166         this.dumperOptions = dumperOptions;
167         this.resolver = resolver;
168         this.name = "Yaml:" + System.identityHashCode(this);
169     }
170 
171     /**
172      * Serialize a Java object into a YAML String.
173      *
174      * @param data
175      *            Java object to be Serialized to YAML
176      * @return YAML String
177      */
dump(Object data)178     public String dump(Object data) {
179         List<Object> list = new ArrayList<Object>(1);
180         list.add(data);
181         return dumpAll(list.iterator());
182     }
183 
184     /**
185      * Produce the corresponding representation tree for a given Object.
186      *
187      * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
188      *      Overview</a>
189      * @param data
190      *            instance to build the representation tree for
191      * @return representation tree
192      */
represent(Object data)193     public Node represent(Object data) {
194         return representer.represent(data);
195     }
196 
197     /**
198      * Serialize a sequence of Java objects into a YAML String.
199      *
200      * @param data
201      *            Iterator with Objects
202      * @return YAML String with all the objects in proper sequence
203      */
dumpAll(Iterator<? extends Object> data)204     public String dumpAll(Iterator<? extends Object> data) {
205         StringWriter buffer = new StringWriter();
206         dumpAll(data, buffer, null);
207         return buffer.toString();
208     }
209 
210     /**
211      * Serialize a Java object into a YAML stream.
212      *
213      * @param data
214      *            Java object to be serialized to YAML
215      * @param output
216      *            stream to write to
217      */
dump(Object data, Writer output)218     public void dump(Object data, Writer output) {
219         List<Object> list = new ArrayList<Object>(1);
220         list.add(data);
221         dumpAll(list.iterator(), output, null);
222     }
223 
224     /**
225      * Serialize a sequence of Java objects into a YAML stream.
226      *
227      * @param data
228      *            Iterator with Objects
229      * @param output
230      *            stream to write to
231      */
dumpAll(Iterator<? extends Object> data, Writer output)232     public void dumpAll(Iterator<? extends Object> data, Writer output) {
233         dumpAll(data, output, null);
234     }
235 
dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag)236     private void dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag) {
237         Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver,
238                 dumperOptions, rootTag);
239         try {
240             serializer.open();
241             while (data.hasNext()) {
242                 Node node = representer.represent(data.next());
243                 serializer.serialize(node);
244             }
245             serializer.close();
246         } catch (IOException e) {
247             throw new YAMLException(e);
248         }
249     }
250 
251     /**
252      * <p>
253      * Serialize a Java object into a YAML string. Override the default root tag
254      * with <code>rootTag</code>.
255      * </p>
256      *
257      * <p>
258      * This method is similar to <code>Yaml.dump(data)</code> except that the
259      * root tag for the whole document is replaced with the given tag. This has
260      * two main uses.
261      * </p>
262      *
263      * <p>
264      * First, if the root tag is replaced with a standard YAML tag, such as
265      * <code>Tag.MAP</code>, then the object will be dumped as a map. The root
266      * tag will appear as <code>!!map</code>, or blank (implicit !!map).
267      * </p>
268      *
269      * <p>
270      * Second, if the root tag is replaced by a different custom tag, then the
271      * document appears to be a different type when loaded. For example, if an
272      * instance of MyClass is dumped with the tag !!YourClass, then it will be
273      * handled as an instance of YourClass when loaded.
274      * </p>
275      *
276      * @param data
277      *            Java object to be serialized to YAML
278      * @param rootTag
279      *            the tag for the whole YAML document. The tag should be Tag.MAP
280      *            for a JavaBean to make the tag disappear (to use implicit tag
281      *            !!map). If <code>null</code> is provided then the standard tag
282      *            with the full class name is used.
283      * @param flowStyle
284      *            flow style for the whole document. See Chapter 10. Collection
285      *            Styles http://yaml.org/spec/1.1/#id930798. If
286      *            <code>null</code> is provided then the flow style from
287      *            DumperOptions is used.
288      *
289      * @return YAML String
290      */
dumpAs(Object data, Tag rootTag, FlowStyle flowStyle)291     public String dumpAs(Object data, Tag rootTag, FlowStyle flowStyle) {
292         FlowStyle oldStyle = representer.getDefaultFlowStyle();
293         if (flowStyle != null) {
294             representer.setDefaultFlowStyle(flowStyle);
295         }
296         List<Object> list = new ArrayList<Object>(1);
297         list.add(data);
298         StringWriter buffer = new StringWriter();
299         dumpAll(list.iterator(), buffer, rootTag);
300         representer.setDefaultFlowStyle(oldStyle);
301         return buffer.toString();
302     }
303 
304     /**
305      * <p>
306      * Serialize a Java object into a YAML string. Override the default root tag
307      * with <code>Tag.MAP</code>.
308      * </p>
309      * <p>
310      * This method is similar to <code>Yaml.dump(data)</code> except that the
311      * root tag for the whole document is replaced with <code>Tag.MAP</code> tag
312      * (implicit !!map).
313      * </p>
314      * <p>
315      * Block Mapping is used as the collection style. See 10.2.2. Block Mappings
316      * (http://yaml.org/spec/1.1/#id934537)
317      * </p>
318      *
319      * @param data
320      *            Java object to be serialized to YAML
321      * @return YAML String
322      */
dumpAsMap(Object data)323     public String dumpAsMap(Object data) {
324         return dumpAs(data, Tag.MAP, FlowStyle.BLOCK);
325     }
326 
327     /**
328      * Serialize the representation tree into Events.
329      *
330      * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
331      * @param data
332      *            representation tree
333      * @return Event list
334      */
serialize(Node data)335     public List<Event> serialize(Node data) {
336         SilentEmitter emitter = new SilentEmitter();
337         Serializer serializer = new Serializer(emitter, resolver, dumperOptions, null);
338         try {
339             serializer.open();
340             serializer.serialize(data);
341             serializer.close();
342         } catch (IOException e) {
343             throw new YAMLException(e);
344         }
345         return emitter.getEvents();
346     }
347 
348     private static class SilentEmitter implements Emitable {
349         private List<Event> events = new ArrayList<Event>(100);
350 
getEvents()351         public List<Event> getEvents() {
352             return events;
353         }
354 
emit(Event event)355         public void emit(Event event) throws IOException {
356             events.add(event);
357         }
358     }
359 
360     /**
361      * Parse the only YAML document in a String and produce the corresponding
362      * Java object. (Because the encoding in known BOM is not respected.)
363      *
364      * @param yaml
365      *            YAML data to load from (BOM must not be present)
366      * @return parsed object
367      */
load(String yaml)368     public Object load(String yaml) {
369         return loadFromReader(new StreamReader(yaml), Object.class);
370     }
371 
372     /**
373      * Parse the only YAML document in a stream and produce the corresponding
374      * Java object.
375      *
376      * @param io
377      *            data to load from (BOM is respected and removed)
378      * @return parsed object
379      */
load(InputStream io)380     public Object load(InputStream io) {
381         return loadFromReader(new StreamReader(new UnicodeReader(io)), Object.class);
382     }
383 
384     /**
385      * Parse the only YAML document in a stream and produce the corresponding
386      * Java object.
387      *
388      * @param io
389      *            data to load from (BOM must not be present)
390      * @return parsed object
391      */
load(Reader io)392     public Object load(Reader io) {
393         return loadFromReader(new StreamReader(io), Object.class);
394     }
395 
396     /**
397      * Parse the only YAML document in a stream and produce the corresponding
398      * Java object.
399      *
400      * @param <T>
401      *            Class is defined by the second argument
402      * @param io
403      *            data to load from (BOM must not be present)
404      * @param type
405      *            Class of the object to be created
406      * @return parsed object
407      */
408     @SuppressWarnings("unchecked")
loadAs(Reader io, Class<T> type)409     public <T> T loadAs(Reader io, Class<T> type) {
410         return (T) loadFromReader(new StreamReader(io), type);
411     }
412 
413     /**
414      * Parse the only YAML document in a String and produce the corresponding
415      * Java object. (Because the encoding in known BOM is not respected.)
416      *
417      * @param <T>
418      *            Class is defined by the second argument
419      * @param yaml
420      *            YAML data to load from (BOM must not be present)
421      * @param type
422      *            Class of the object to be created
423      * @return parsed object
424      */
425     @SuppressWarnings("unchecked")
loadAs(String yaml, Class<T> type)426     public <T> T loadAs(String yaml, Class<T> type) {
427         return (T) loadFromReader(new StreamReader(yaml), type);
428     }
429 
430     /**
431      * Parse the only YAML document in a stream and produce the corresponding
432      * Java object.
433      *
434      * @param <T>
435      *            Class is defined by the second argument
436      * @param input
437      *            data to load from (BOM is respected and removed)
438      * @param type
439      *            Class of the object to be created
440      * @return parsed object
441      */
442     @SuppressWarnings("unchecked")
loadAs(InputStream input, Class<T> type)443     public <T> T loadAs(InputStream input, Class<T> type) {
444         return (T) loadFromReader(new StreamReader(new UnicodeReader(input)), type);
445     }
446 
loadFromReader(StreamReader sreader, Class<?> type)447     private Object loadFromReader(StreamReader sreader, Class<?> type) {
448         Composer composer = new Composer(new ParserImpl(sreader), resolver);
449         constructor.setComposer(composer);
450         return constructor.getSingleData(type);
451     }
452 
453     /**
454      * Parse all YAML documents in a String and produce corresponding Java
455      * objects. The documents are parsed only when the iterator is invoked.
456      *
457      * @param yaml
458      *            YAML data to load from (BOM must not be present)
459      * @return an iterator over the parsed Java objects in this String in proper
460      *         sequence
461      */
loadAll(Reader yaml)462     public Iterable<Object> loadAll(Reader yaml) {
463         Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
464         constructor.setComposer(composer);
465         Iterator<Object> result = new Iterator<Object>() {
466             public boolean hasNext() {
467                 return constructor.checkData();
468             }
469 
470             public Object next() {
471                 return constructor.getData();
472             }
473 
474             public void remove() {
475                 throw new UnsupportedOperationException();
476             }
477         };
478         return new YamlIterable(result);
479     }
480 
481     private static class YamlIterable implements Iterable<Object> {
482         private Iterator<Object> iterator;
483 
YamlIterable(Iterator<Object> iterator)484         public YamlIterable(Iterator<Object> iterator) {
485             this.iterator = iterator;
486         }
487 
iterator()488         public Iterator<Object> iterator() {
489             return iterator;
490         }
491     }
492 
493     /**
494      * Parse all YAML documents in a String and produce corresponding Java
495      * objects. (Because the encoding in known BOM is not respected.) The
496      * documents are parsed only when the iterator is invoked.
497      *
498      * @param yaml
499      *            YAML data to load from (BOM must not be present)
500      * @return an iterator over the parsed Java objects in this String in proper
501      *         sequence
502      */
loadAll(String yaml)503     public Iterable<Object> loadAll(String yaml) {
504         return loadAll(new StringReader(yaml));
505     }
506 
507     /**
508      * Parse all YAML documents in a stream and produce corresponding Java
509      * objects. The documents are parsed only when the iterator is invoked.
510      *
511      * @param yaml
512      *            YAML data to load from (BOM is respected and ignored)
513      * @return an iterator over the parsed Java objects in this stream in proper
514      *         sequence
515      */
loadAll(InputStream yaml)516     public Iterable<Object> loadAll(InputStream yaml) {
517         return loadAll(new UnicodeReader(yaml));
518     }
519 
520     /**
521      * Parse the first YAML document in a stream and produce the corresponding
522      * representation tree. (This is the opposite of the represent() method)
523      *
524      * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing
525      *      Overview</a>
526      * @param yaml
527      *            YAML document
528      * @return parsed root Node for the specified YAML document
529      */
compose(Reader yaml)530     public Node compose(Reader yaml) {
531         Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
532         constructor.setComposer(composer);
533         return composer.getSingleNode();
534     }
535 
536     /**
537      * Parse all YAML documents in a stream and produce corresponding
538      * representation trees.
539      *
540      * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
541      * @param yaml
542      *            stream of YAML documents
543      * @return parsed root Nodes for all the specified YAML documents
544      */
composeAll(Reader yaml)545     public Iterable<Node> composeAll(Reader yaml) {
546         final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver);
547         constructor.setComposer(composer);
548         Iterator<Node> result = new Iterator<Node>() {
549             public boolean hasNext() {
550                 return composer.checkNode();
551             }
552 
553             public Node next() {
554                 return composer.getNode();
555             }
556 
557             public void remove() {
558                 throw new UnsupportedOperationException();
559             }
560         };
561         return new NodeIterable(result);
562     }
563 
564     private static class NodeIterable implements Iterable<Node> {
565         private Iterator<Node> iterator;
566 
NodeIterable(Iterator<Node> iterator)567         public NodeIterable(Iterator<Node> iterator) {
568             this.iterator = iterator;
569         }
570 
iterator()571         public Iterator<Node> iterator() {
572             return iterator;
573         }
574     }
575 
576     /**
577      * Add an implicit scalar detector. If an implicit scalar value matches the
578      * given regexp, the corresponding tag is assigned to the scalar.
579      *
580      * @param tag
581      *            tag to assign to the node
582      * @param regexp
583      *            regular expression to match against
584      * @param first
585      *            a sequence of possible initial characters or null (which means
586      *            any).
587      */
addImplicitResolver(Tag tag, Pattern regexp, String first)588     public void addImplicitResolver(Tag tag, Pattern regexp, String first) {
589         resolver.addImplicitResolver(tag, regexp, first);
590     }
591 
592     @Override
toString()593     public String toString() {
594         return name;
595     }
596 
597     /**
598      * Get a meaningful name. It simplifies debugging in a multi-threaded
599      * environment. If nothing is set explicitly the address of the instance is
600      * returned.
601      *
602      * @return human readable name
603      */
getName()604     public String getName() {
605         return name;
606     }
607 
608     /**
609      * Set a meaningful name to be shown in toString()
610      *
611      * @param name
612      *            human readable name
613      */
setName(String name)614     public void setName(String name) {
615         this.name = name;
616     }
617 
618     /**
619      * Parse a YAML stream and produce parsing events.
620      *
621      * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a>
622      * @param yaml
623      *            YAML document(s)
624      * @return parsed events
625      */
parse(Reader yaml)626     public Iterable<Event> parse(Reader yaml) {
627         final Parser parser = new ParserImpl(new StreamReader(yaml));
628         Iterator<Event> result = new Iterator<Event>() {
629             public boolean hasNext() {
630                 return parser.peekEvent() != null;
631             }
632 
633             public Event next() {
634                 return parser.getEvent();
635             }
636 
637             public void remove() {
638                 throw new UnsupportedOperationException();
639             }
640         };
641         return new EventIterable(result);
642     }
643 
644     private static class EventIterable implements Iterable<Event> {
645         private Iterator<Event> iterator;
646 
EventIterable(Iterator<Event> iterator)647         public EventIterable(Iterator<Event> iterator) {
648             this.iterator = iterator;
649         }
650 
iterator()651         public Iterator<Event> iterator() {
652             return iterator;
653         }
654     }
655 
setBeanAccess(BeanAccess beanAccess)656     public void setBeanAccess(BeanAccess beanAccess) {
657         constructor.getPropertyUtils().setBeanAccess(beanAccess);
658         representer.getPropertyUtils().setBeanAccess(beanAccess);
659     }
660 
661 }
662