| /** |
| * Copyright (c) 2008-2014, http://www.snakeyaml.org |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.yaml.snakeyaml; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| |
| import org.yaml.snakeyaml.DumperOptions.FlowStyle; |
| import org.yaml.snakeyaml.composer.Composer; |
| import org.yaml.snakeyaml.constructor.BaseConstructor; |
| import org.yaml.snakeyaml.constructor.Constructor; |
| import org.yaml.snakeyaml.emitter.Emitable; |
| import org.yaml.snakeyaml.emitter.Emitter; |
| import org.yaml.snakeyaml.error.YAMLException; |
| import org.yaml.snakeyaml.events.Event; |
| import org.yaml.snakeyaml.introspector.BeanAccess; |
| import org.yaml.snakeyaml.nodes.Node; |
| import org.yaml.snakeyaml.nodes.Tag; |
| import org.yaml.snakeyaml.parser.Parser; |
| import org.yaml.snakeyaml.parser.ParserImpl; |
| import org.yaml.snakeyaml.reader.StreamReader; |
| import org.yaml.snakeyaml.reader.UnicodeReader; |
| import org.yaml.snakeyaml.representer.Representer; |
| import org.yaml.snakeyaml.resolver.Resolver; |
| import org.yaml.snakeyaml.serializer.Serializer; |
| |
| /** |
| * Public YAML interface. Each Thread must have its own instance. |
| */ |
| public class Yaml { |
| protected final Resolver resolver; |
| private String name; |
| protected BaseConstructor constructor; |
| protected Representer representer; |
| protected DumperOptions dumperOptions; |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| */ |
| public Yaml() { |
| this(new Constructor(), new Representer(), new DumperOptions(), new Resolver()); |
| } |
| |
| /** |
| * @deprecated |
| */ |
| public Yaml(LoaderOptions loaderOptions) { |
| this(new Constructor(), new Representer(), new DumperOptions(), new Resolver()); |
| } |
| |
| /** |
| * Create Yaml instance. |
| * |
| * @param dumperOptions |
| * DumperOptions to configure outgoing objects |
| */ |
| public Yaml(DumperOptions dumperOptions) { |
| this(new Constructor(), new Representer(), dumperOptions); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param representer |
| * Representer to emit outgoing objects |
| */ |
| public Yaml(Representer representer) { |
| this(new Constructor(), representer); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param constructor |
| * BaseConstructor to construct incoming documents |
| */ |
| public Yaml(BaseConstructor constructor) { |
| this(constructor, new Representer()); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param constructor |
| * BaseConstructor to construct incoming documents |
| * @param representer |
| * Representer to emit outgoing objects |
| */ |
| public Yaml(BaseConstructor constructor, Representer representer) { |
| this(constructor, representer, new DumperOptions()); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param representer |
| * Representer to emit outgoing objects |
| * @param dumperOptions |
| * DumperOptions to configure outgoing objects |
| */ |
| public Yaml(Representer representer, DumperOptions dumperOptions) { |
| this(new Constructor(), representer, dumperOptions, new Resolver()); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param constructor |
| * BaseConstructor to construct incoming documents |
| * @param representer |
| * Representer to emit outgoing objects |
| * @param dumperOptions |
| * DumperOptions to configure outgoing objects |
| */ |
| public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions) { |
| this(constructor, representer, dumperOptions, new Resolver()); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param constructor |
| * BaseConstructor to construct incoming documents |
| * @param representer |
| * Representer to emit outgoing objects |
| * @param dumperOptions |
| * DumperOptions to configure outgoing objects |
| * @param resolver |
| * Resolver to detect implicit type |
| */ |
| public Yaml(BaseConstructor constructor, Representer representer, DumperOptions dumperOptions, |
| Resolver resolver) { |
| if (!constructor.isExplicitPropertyUtils()) { |
| constructor.setPropertyUtils(representer.getPropertyUtils()); |
| } else if (!representer.isExplicitPropertyUtils()) { |
| representer.setPropertyUtils(constructor.getPropertyUtils()); |
| } |
| this.constructor = constructor; |
| representer.setDefaultFlowStyle(dumperOptions.getDefaultFlowStyle()); |
| representer.setDefaultScalarStyle(dumperOptions.getDefaultScalarStyle()); |
| representer.getPropertyUtils().setAllowReadOnlyProperties( |
| dumperOptions.isAllowReadOnlyProperties()); |
| representer.setTimeZone(dumperOptions.getTimeZone()); |
| this.representer = representer; |
| this.dumperOptions = dumperOptions; |
| this.resolver = resolver; |
| this.name = "Yaml:" + System.identityHashCode(this); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param constructor |
| * BaseConstructor to construct incoming documents |
| * @param loaderOptions |
| * LoaderOptions to control construction process (unused) |
| * @param representer |
| * Representer to emit outgoing objects |
| * @param dumperOptions |
| * DumperOptions to configure outgoing objects |
| * @param resolver |
| * Resolver to detect implicit type |
| * @deprecated |
| */ |
| public Yaml(BaseConstructor constructor, LoaderOptions loaderOptions, Representer representer, |
| DumperOptions dumperOptions, Resolver resolver) { |
| this(constructor, representer, dumperOptions, resolver); |
| } |
| |
| /** |
| * Serialize a Java object into a YAML String. |
| * |
| * @param data |
| * Java object to be Serialized to YAML |
| * @return YAML String |
| */ |
| public String dump(Object data) { |
| List<Object> list = new ArrayList<Object>(1); |
| list.add(data); |
| return dumpAll(list.iterator()); |
| } |
| |
| /** |
| * Produce the corresponding representation tree for a given Object. |
| * |
| * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing |
| * Overview</a> |
| * @param data |
| * instance to build the representation tree for |
| * @return representation tree |
| */ |
| public Node represent(Object data) { |
| return representer.represent(data); |
| } |
| |
| /** |
| * Serialize a sequence of Java objects into a YAML String. |
| * |
| * @param data |
| * Iterator with Objects |
| * @return YAML String with all the objects in proper sequence |
| */ |
| public String dumpAll(Iterator<? extends Object> data) { |
| StringWriter buffer = new StringWriter(); |
| dumpAll(data, buffer); |
| return buffer.toString(); |
| } |
| |
| /** |
| * Serialize a Java object into a YAML stream. |
| * |
| * @param data |
| * Java object to be serialized to YAML |
| * @param output |
| * stream to write to |
| */ |
| public void dump(Object data, Writer output) { |
| List<Object> list = new ArrayList<Object>(1); |
| list.add(data); |
| dumpAll(list.iterator(), output); |
| } |
| |
| /** |
| * Serialize a sequence of Java objects into a YAML stream. |
| * |
| * @param data |
| * Iterator with Objects |
| * @param output |
| * stream to write to |
| */ |
| @SuppressWarnings("deprecation") |
| public void dumpAll(Iterator<? extends Object> data, Writer output) { |
| dumpAll(data, output, dumperOptions.getExplicitRoot()); |
| } |
| |
| private void dumpAll(Iterator<? extends Object> data, Writer output, Tag rootTag) { |
| Serializer serializer = new Serializer(new Emitter(output, dumperOptions), resolver, |
| dumperOptions, rootTag); |
| try { |
| serializer.open(); |
| while (data.hasNext()) { |
| Node node = representer.represent(data.next()); |
| serializer.serialize(node); |
| } |
| serializer.close(); |
| } catch (java.io.IOException e) { |
| throw new YAMLException(e); |
| } |
| } |
| |
| /** |
| * <p> |
| * Serialize a Java object into a YAML string. Override the default root tag |
| * with <code>rootTag</code>. |
| * </p> |
| * |
| * <p> |
| * This method is similar to <code>Yaml.dump(data)</code> except that the |
| * root tag for the whole document is replaced with the given tag. This has |
| * two main uses. |
| * </p> |
| * |
| * <p> |
| * First, if the root tag is replaced with a standard YAML tag, such as |
| * <code>Tag.MAP</code>, then the object will be dumped as a map. The root |
| * tag will appear as <code>!!map</code>, or blank (implicit !!map). |
| * </p> |
| * |
| * <p> |
| * Second, if the root tag is replaced by a different custom tag, then the |
| * document appears to be a different type when loaded. For example, if an |
| * instance of MyClass is dumped with the tag !!YourClass, then it will be |
| * handled as an instance of YourClass when loaded. |
| * </p> |
| * |
| * @param data |
| * Java object to be serialized to YAML |
| * @param rootTag |
| * the tag for the whole YAML document. The tag should be Tag.MAP |
| * for a JavaBean to make the tag disappear (to use implicit tag |
| * !!map). If <code>null</code> is provided then the standard tag |
| * with the full class name is used. |
| * @param flowStyle |
| * flow style for the whole document. See Chapter 10. Collection |
| * Styles http://yaml.org/spec/1.1/#id930798. If |
| * <code>null</code> is provided then the flow style from |
| * DumperOptions is used. |
| * |
| * @return YAML String |
| */ |
| public String dumpAs(Object data, Tag rootTag, FlowStyle flowStyle) { |
| FlowStyle oldStyle = representer.getDefaultFlowStyle(); |
| if (flowStyle != null) { |
| representer.setDefaultFlowStyle(flowStyle); |
| } |
| List<Object> list = new ArrayList<Object>(1); |
| list.add(data); |
| StringWriter buffer = new StringWriter(); |
| dumpAll(list.iterator(), buffer, rootTag); |
| representer.setDefaultFlowStyle(oldStyle); |
| return buffer.toString(); |
| } |
| |
| /** |
| * <p> |
| * Serialize a Java object into a YAML string. Override the default root tag |
| * with <code>Tag.MAP</code>. |
| * </p> |
| * <p> |
| * This method is similar to <code>Yaml.dump(data)</code> except that the |
| * root tag for the whole document is replaced with <code>Tag.MAP</code> tag |
| * (implicit !!map). |
| * </p> |
| * <p> |
| * Block Mapping is used as the collection style. See 10.2.2. Block Mappings |
| * (http://yaml.org/spec/1.1/#id934537) |
| * </p> |
| * |
| * @param data |
| * Java object to be serialized to YAML |
| * @return YAML String |
| */ |
| public String dumpAsMap(Object data) { |
| return dumpAs(data, Tag.MAP, FlowStyle.BLOCK); |
| } |
| |
| /** |
| * Serialize the representation tree into Events. |
| * |
| * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a> |
| * @param data |
| * representation tree |
| * @return Event list |
| */ |
| public List<Event> serialize(Node data) { |
| SilentEmitter emitter = new SilentEmitter(); |
| @SuppressWarnings("deprecation") |
| Serializer serializer = new Serializer(emitter, resolver, dumperOptions, |
| dumperOptions.getExplicitRoot()); |
| try { |
| serializer.open(); |
| serializer.serialize(data); |
| serializer.close(); |
| } catch (java.io.IOException e) { |
| throw new YAMLException(e); |
| } |
| return emitter.getEvents(); |
| } |
| |
| private static class SilentEmitter implements Emitable { |
| private List<Event> events = new ArrayList<Event>(100); |
| |
| public List<Event> getEvents() { |
| return events; |
| } |
| |
| public void emit(Event event) throws IOException { |
| events.add(event); |
| } |
| } |
| |
| /** |
| * Parse the only YAML document in a String and produce the corresponding |
| * Java object. (Because the encoding in known BOM is not respected.) |
| * |
| * @param yaml |
| * YAML data to load from (BOM must not be present) |
| * @return parsed object |
| */ |
| public Object load(String yaml) { |
| return loadFromReader(new StreamReader(yaml), Object.class); |
| } |
| |
| /** |
| * Parse the only YAML document in a stream and produce the corresponding |
| * Java object. |
| * |
| * @param io |
| * data to load from (BOM is respected and removed) |
| * @return parsed object |
| */ |
| public Object load(InputStream io) { |
| return loadFromReader(new StreamReader(new UnicodeReader(io)), Object.class); |
| } |
| |
| /** |
| * Parse the only YAML document in a stream and produce the corresponding |
| * Java object. |
| * |
| * @param io |
| * data to load from (BOM must not be present) |
| * @return parsed object |
| */ |
| public Object load(Reader io) { |
| return loadFromReader(new StreamReader(io), Object.class); |
| } |
| |
| /** |
| * Parse the only YAML document in a stream and produce the corresponding |
| * Java object. |
| * |
| * @param <T> |
| * Class is defined by the second argument |
| * @param io |
| * data to load from (BOM must not be present) |
| * @param type |
| * Class of the object to be created |
| * @return parsed object |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> T loadAs(Reader io, Class<T> type) { |
| return (T) loadFromReader(new StreamReader(io), type); |
| } |
| |
| /** |
| * Parse the only YAML document in a String and produce the corresponding |
| * Java object. (Because the encoding in known BOM is not respected.) |
| * |
| * @param <T> |
| * Class is defined by the second argument |
| * @param yaml |
| * YAML data to load from (BOM must not be present) |
| * @param type |
| * Class of the object to be created |
| * @return parsed object |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> T loadAs(String yaml, Class<T> type) { |
| return (T) loadFromReader(new StreamReader(yaml), type); |
| } |
| |
| /** |
| * Parse the only YAML document in a stream and produce the corresponding |
| * Java object. |
| * |
| * @param <T> |
| * Class is defined by the second argument |
| * @param input |
| * data to load from (BOM is respected and removed) |
| * @param type |
| * Class of the object to be created |
| * @return parsed object |
| */ |
| @SuppressWarnings("unchecked") |
| public <T> T loadAs(InputStream input, Class<T> type) { |
| return (T) loadFromReader(new StreamReader(new UnicodeReader(input)), type); |
| } |
| |
| private Object loadFromReader(StreamReader sreader, Class<?> type) { |
| Composer composer = new Composer(new ParserImpl(sreader), resolver); |
| constructor.setComposer(composer); |
| return constructor.getSingleData(type); |
| } |
| |
| /** |
| * Parse all YAML documents in a String and produce corresponding Java |
| * objects. The documents are parsed only when the iterator is invoked. |
| * |
| * @param yaml |
| * YAML data to load from (BOM must not be present) |
| * @return an iterator over the parsed Java objects in this String in proper |
| * sequence |
| */ |
| public Iterable<Object> loadAll(Reader yaml) { |
| Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver); |
| constructor.setComposer(composer); |
| Iterator<Object> result = new Iterator<Object>() { |
| public boolean hasNext() { |
| return constructor.checkData(); |
| } |
| |
| public Object next() { |
| return constructor.getData(); |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| return new YamlIterable(result); |
| } |
| |
| private static class YamlIterable implements Iterable<Object> { |
| private Iterator<Object> iterator; |
| |
| public YamlIterable(Iterator<Object> iterator) { |
| this.iterator = iterator; |
| } |
| |
| public Iterator<Object> iterator() { |
| return iterator; |
| } |
| } |
| |
| /** |
| * Parse all YAML documents in a String and produce corresponding Java |
| * objects. (Because the encoding in known BOM is not respected.) The |
| * documents are parsed only when the iterator is invoked. |
| * |
| * @param yaml |
| * YAML data to load from (BOM must not be present) |
| * @return an iterator over the parsed Java objects in this String in proper |
| * sequence |
| */ |
| public Iterable<Object> loadAll(String yaml) { |
| return loadAll(new StringReader(yaml)); |
| } |
| |
| /** |
| * Parse all YAML documents in a stream and produce corresponding Java |
| * objects. The documents are parsed only when the iterator is invoked. |
| * |
| * @param yaml |
| * YAML data to load from (BOM is respected and ignored) |
| * @return an iterator over the parsed Java objects in this stream in proper |
| * sequence |
| */ |
| public Iterable<Object> loadAll(InputStream yaml) { |
| return loadAll(new UnicodeReader(yaml)); |
| } |
| |
| /** |
| * Parse the first YAML document in a stream and produce the corresponding |
| * representation tree. (This is the opposite of the represent() method) |
| * |
| * @see <a href="http://yaml.org/spec/1.1/#id859333">Figure 3.1. Processing |
| * Overview</a> |
| * @param yaml |
| * YAML document |
| * @return parsed root Node for the specified YAML document |
| */ |
| public Node compose(Reader yaml) { |
| Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver); |
| constructor.setComposer(composer); |
| return composer.getSingleNode(); |
| } |
| |
| /** |
| * Parse all YAML documents in a stream and produce corresponding |
| * representation trees. |
| * |
| * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a> |
| * @param yaml |
| * stream of YAML documents |
| * @return parsed root Nodes for all the specified YAML documents |
| */ |
| public Iterable<Node> composeAll(Reader yaml) { |
| final Composer composer = new Composer(new ParserImpl(new StreamReader(yaml)), resolver); |
| constructor.setComposer(composer); |
| Iterator<Node> result = new Iterator<Node>() { |
| public boolean hasNext() { |
| return composer.checkNode(); |
| } |
| |
| public Node next() { |
| return composer.getNode(); |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| return new NodeIterable(result); |
| } |
| |
| private static class NodeIterable implements Iterable<Node> { |
| private Iterator<Node> iterator; |
| |
| public NodeIterable(Iterator<Node> iterator) { |
| this.iterator = iterator; |
| } |
| |
| public Iterator<Node> iterator() { |
| return iterator; |
| } |
| } |
| |
| /** |
| * Add an implicit scalar detector. If an implicit scalar value matches the |
| * given regexp, the corresponding tag is assigned to the scalar. |
| * |
| * @deprecated use Tag instead of String |
| * @param tag |
| * tag to assign to the node |
| * @param regexp |
| * regular expression to match against |
| * @param first |
| * a sequence of possible initial characters or null (which means |
| * any). |
| * |
| */ |
| public void addImplicitResolver(String tag, Pattern regexp, String first) { |
| addImplicitResolver(new Tag(tag), regexp, first); |
| } |
| |
| /** |
| * Add an implicit scalar detector. If an implicit scalar value matches the |
| * given regexp, the corresponding tag is assigned to the scalar. |
| * |
| * @param tag |
| * tag to assign to the node |
| * @param regexp |
| * regular expression to match against |
| * @param first |
| * a sequence of possible initial characters or null (which means |
| * any). |
| */ |
| public void addImplicitResolver(Tag tag, Pattern regexp, String first) { |
| resolver.addImplicitResolver(tag, regexp, first); |
| } |
| |
| @Override |
| public String toString() { |
| return name; |
| } |
| |
| /** |
| * Get a meaningful name. It simplifies debugging in a multi-threaded |
| * environment. If nothing is set explicitly the address of the instance is |
| * returned. |
| * |
| * @return human readable name |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Set a meaningful name to be shown in toString() |
| * |
| * @param name |
| * human readable name |
| */ |
| public void setName(String name) { |
| this.name = name; |
| } |
| |
| /** |
| * Parse a YAML stream and produce parsing events. |
| * |
| * @see <a href="http://yaml.org/spec/1.1/#id859333">Processing Overview</a> |
| * @param yaml |
| * YAML document(s) |
| * @return parsed events |
| */ |
| public Iterable<Event> parse(Reader yaml) { |
| final Parser parser = new ParserImpl(new StreamReader(yaml)); |
| Iterator<Event> result = new Iterator<Event>() { |
| public boolean hasNext() { |
| return parser.peekEvent() != null; |
| } |
| |
| public Event next() { |
| return parser.getEvent(); |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| }; |
| return new EventIterable(result); |
| } |
| |
| private static class EventIterable implements Iterable<Event> { |
| private Iterator<Event> iterator; |
| |
| public EventIterable(Iterator<Event> iterator) { |
| this.iterator = iterator; |
| } |
| |
| public Iterator<Event> iterator() { |
| return iterator; |
| } |
| } |
| |
| public void setBeanAccess(BeanAccess beanAccess) { |
| constructor.getPropertyUtils().setBeanAccess(beanAccess); |
| representer.getPropertyUtils().setBeanAccess(beanAccess); |
| } |
| |
| // deprecated |
| /** |
| * @deprecated use with Constructor instead of Loader |
| */ |
| public Yaml(Loader loader) { |
| this(loader, new Dumper(new DumperOptions())); |
| } |
| |
| /** |
| * @deprecated use with Constructor instead of Loader |
| */ |
| public Yaml(Loader loader, Dumper dumper) { |
| this(loader, dumper, new Resolver()); |
| } |
| |
| /** |
| * @deprecated use with Constructor instead of Loader |
| */ |
| public Yaml(Loader loader, Dumper dumper, Resolver resolver) { |
| this(loader.constructor, dumper.representer, dumper.options, resolver); |
| } |
| |
| /** |
| * Create Yaml instance. It is safe to create a few instances and use them |
| * in different Threads. |
| * |
| * @param dumper |
| * Dumper to emit outgoing objects |
| */ |
| @SuppressWarnings("deprecation") |
| public Yaml(Dumper dumper) { |
| this(new Constructor(), dumper.representer, dumper.options); |
| } |
| } |