View Javadoc

1   /**
2    * Copyright (c) 2008-2012, 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.representer;
17  
18  import java.util.ArrayList;
19  import java.util.HashMap;
20  import java.util.IdentityHashMap;
21  import java.util.LinkedHashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.yaml.snakeyaml.DumperOptions.FlowStyle;
26  import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
27  import org.yaml.snakeyaml.error.YAMLException;
28  import org.yaml.snakeyaml.introspector.PropertyUtils;
29  import org.yaml.snakeyaml.nodes.AnchorNode;
30  import org.yaml.snakeyaml.nodes.MappingNode;
31  import org.yaml.snakeyaml.nodes.Node;
32  import org.yaml.snakeyaml.nodes.NodeTuple;
33  import org.yaml.snakeyaml.nodes.ScalarNode;
34  import org.yaml.snakeyaml.nodes.SequenceNode;
35  import org.yaml.snakeyaml.nodes.Tag;
36  
37  /**
38   * Represent basic YAML structures: scalar, sequence, mapping
39   */
40  public abstract class BaseRepresenter {
41      protected final Map<Class<?>, Represent> representers = new HashMap<Class<?>, Represent>();
42      /**
43       * in Java 'null' is not a type. So we have to keep the null representer
44       * separately otherwise it will coincide with the default representer which
45       * is stored with the key null.
46       */
47      protected Represent nullRepresenter;
48      // the order is important (map can be also a sequence of key-values)
49      protected final Map<Class<?>, Represent> multiRepresenters = new LinkedHashMap<Class<?>, Represent>();
50      protected Character defaultScalarStyle;
51      protected FlowStyle defaultFlowStyle = FlowStyle.AUTO;
52      protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>() {
53          private static final long serialVersionUID = -5576159264232131854L;
54  
55          public Node put(Object key, Node value) {
56              return super.put(key, new AnchorNode(value));
57          }
58      };
59  
60      protected Object objectToRepresent;
61      private PropertyUtils propertyUtils;
62      private boolean explicitPropertyUtils = false;
63  
64      public Node represent(Object data) {
65          Node node = representData(data);
66          representedObjects.clear();
67          objectToRepresent = null;
68          return node;
69      }
70  
71      protected final Node representData(Object data) {
72          objectToRepresent = data;
73          // check for identity
74          if (representedObjects.containsKey(objectToRepresent)) {
75              Node node = representedObjects.get(objectToRepresent);
76              return node;
77          }
78          // }
79          // check for null first
80          if (data == null) {
81              Node node = nullRepresenter.representData(null);
82              return node;
83          }
84          // check the same class
85          Node node;
86          Class<?> clazz = data.getClass();
87          if (representers.containsKey(clazz)) {
88              Represent representer = representers.get(clazz);
89              node = representer.representData(data);
90          } else {
91              // check the parents
92              for (Class<?> repr : multiRepresenters.keySet()) {
93                  if (repr.isInstance(data)) {
94                      Represent representer = multiRepresenters.get(repr);
95                      node = representer.representData(data);
96                      return node;
97                  }
98              }
99              // check array of primitives
100             if (clazz.isArray()) {
101                 throw new YAMLException("Arrays of primitives are not fully supported.");
102             }
103             // check defaults
104             if (multiRepresenters.containsKey(null)) {
105                 Represent representer = multiRepresenters.get(null);
106                 node = representer.representData(data);
107             } else {
108                 Represent representer = representers.get(null);
109                 node = representer.representData(data);
110             }
111         }
112         return node;
113     }
114 
115     protected Node representScalar(Tag tag, String value, Character style) {
116         if (style == null) {
117             style = this.defaultScalarStyle;
118         }
119         Node node = new ScalarNode(tag, value, null, null, style);
120         return node;
121     }
122 
123     protected Node representScalar(Tag tag, String value) {
124         return representScalar(tag, value, null);
125     }
126 
127     protected Node representSequence(Tag tag, Iterable<? extends Object> sequence, Boolean flowStyle) {
128         int size = 10;// default for ArrayList
129         if (sequence instanceof List<?>) {
130             size = ((List<?>) sequence).size();
131         }
132         List<Node> value = new ArrayList<Node>(size);
133         SequenceNode node = new SequenceNode(tag, value, flowStyle);
134         representedObjects.put(objectToRepresent, node);
135         boolean bestStyle = true;
136         for (Object item : sequence) {
137             Node nodeItem = representData(item);
138             if (!((nodeItem instanceof ScalarNode && ((ScalarNode) nodeItem).getStyle() == null))) {
139                 bestStyle = false;
140             }
141             value.add(nodeItem);
142         }
143         if (flowStyle == null) {
144             if (defaultFlowStyle != FlowStyle.AUTO) {
145                 node.setFlowStyle(defaultFlowStyle.getStyleBoolean());
146             } else {
147                 node.setFlowStyle(bestStyle);
148             }
149         }
150         return node;
151     }
152 
153     protected Node representMapping(Tag tag, Map<? extends Object, Object> mapping,
154             Boolean flowStyle) {
155         List<NodeTuple> value = new ArrayList<NodeTuple>(mapping.size());
156         MappingNode node = new MappingNode(tag, value, flowStyle);
157         representedObjects.put(objectToRepresent, node);
158         boolean bestStyle = true;
159         for (Map.Entry<? extends Object, Object> entry : mapping.entrySet()) {
160             Node nodeKey = representData(entry.getKey());
161             Node nodeValue = representData(entry.getValue());
162             if (!((nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).getStyle() == null))) {
163                 bestStyle = false;
164             }
165             if (!((nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).getStyle() == null))) {
166                 bestStyle = false;
167             }
168             value.add(new NodeTuple(nodeKey, nodeValue));
169         }
170         if (flowStyle == null) {
171             if (defaultFlowStyle != FlowStyle.AUTO) {
172                 node.setFlowStyle(defaultFlowStyle.getStyleBoolean());
173             } else {
174                 node.setFlowStyle(bestStyle);
175             }
176         }
177         return node;
178     }
179 
180     public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
181         this.defaultScalarStyle = defaultStyle.getChar();
182     }
183 
184     public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
185         this.defaultFlowStyle = defaultFlowStyle;
186     }
187 
188     public FlowStyle getDefaultFlowStyle() {
189         return this.defaultFlowStyle;
190     }
191 
192     public void setPropertyUtils(PropertyUtils propertyUtils) {
193         this.propertyUtils = propertyUtils;
194         this.explicitPropertyUtils = true;
195     }
196 
197     public final PropertyUtils getPropertyUtils() {
198         if (propertyUtils == null) {
199             propertyUtils = new PropertyUtils();
200         }
201         return propertyUtils;
202     }
203 
204     public final boolean isExplicitPropertyUtils() {
205         return explicitPropertyUtils;
206     }
207 }