View Javadoc

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