• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2008, SnakeYAML
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 package org.yaml.snakeyaml.representer;
15 
16 import java.util.ArrayList;
17 import java.util.HashMap;
18 import java.util.IdentityHashMap;
19 import java.util.LinkedHashMap;
20 import java.util.List;
21 import java.util.Map;
22 import org.yaml.snakeyaml.DumperOptions;
23 import org.yaml.snakeyaml.DumperOptions.FlowStyle;
24 import org.yaml.snakeyaml.DumperOptions.ScalarStyle;
25 import org.yaml.snakeyaml.introspector.PropertyUtils;
26 import org.yaml.snakeyaml.nodes.AnchorNode;
27 import org.yaml.snakeyaml.nodes.MappingNode;
28 import org.yaml.snakeyaml.nodes.Node;
29 import org.yaml.snakeyaml.nodes.NodeTuple;
30 import org.yaml.snakeyaml.nodes.ScalarNode;
31 import org.yaml.snakeyaml.nodes.SequenceNode;
32 import org.yaml.snakeyaml.nodes.Tag;
33 
34 /**
35  * Represent basic YAML structures: scalar, sequence, mapping
36  */
37 public abstract class BaseRepresenter {
38 
39   protected final Map<Class<?>, Represent> representers = new HashMap<Class<?>, Represent>();
40   /**
41    * in Java 'null' is not a type. So we have to keep the null representer separately otherwise it
42    * will coincide with the default representer which is stored with the key null.
43    */
44   protected Represent nullRepresenter;
45   // the order is important (map can be also a sequence of key-values)
46   protected final Map<Class<?>, Represent> multiRepresenters =
47       new LinkedHashMap<Class<?>, Represent>();
48   protected DumperOptions.ScalarStyle defaultScalarStyle = null; // not explicitly defined
49   protected FlowStyle defaultFlowStyle = FlowStyle.AUTO;
50   protected final Map<Object, Node> representedObjects = new IdentityHashMap<Object, Node>() {
51     private static final long serialVersionUID = -5576159264232131854L;
52 
53     public Node put(Object key, Node value) {
54       return super.put(key, new AnchorNode(value));
55     }
56   };
57 
58   protected Object objectToRepresent;
59   private PropertyUtils propertyUtils;
60   private boolean explicitPropertyUtils = false;
61 
represent(Object data)62   public Node represent(Object data) {
63     Node node = representData(data);
64     representedObjects.clear();
65     objectToRepresent = null;
66     return node;
67   }
68 
representData(Object data)69   protected final Node representData(Object data) {
70     objectToRepresent = data;
71     // check for identity
72     if (representedObjects.containsKey(objectToRepresent)) {
73       Node node = representedObjects.get(objectToRepresent);
74       return node;
75     }
76     // }
77     // check for null first
78     if (data == null) {
79       Node node = nullRepresenter.representData(null);
80       return node;
81     }
82     // check the same class
83     Node node;
84     Class<?> clazz = data.getClass();
85     if (representers.containsKey(clazz)) {
86       Represent representer = representers.get(clazz);
87       node = representer.representData(data);
88     } else {
89       // check the parents
90       for (Class<?> repr : multiRepresenters.keySet()) {
91         if (repr != null && repr.isInstance(data)) {
92           Represent representer = multiRepresenters.get(repr);
93           node = representer.representData(data);
94           return node;
95         }
96       }
97 
98       // check defaults
99       if (multiRepresenters.containsKey(null)) {
100         Represent representer = multiRepresenters.get(null);
101         node = representer.representData(data);
102       } else {
103         Represent representer = representers.get(null);
104         node = representer.representData(data);
105       }
106     }
107     return node;
108   }
109 
representScalar(Tag tag, String value, DumperOptions.ScalarStyle style)110   protected Node representScalar(Tag tag, String value, DumperOptions.ScalarStyle style) {
111     if (style == null) {
112       style = this.defaultScalarStyle;
113     }
114     Node node = new ScalarNode(tag, value, null, null, style);
115     return node;
116   }
117 
representScalar(Tag tag, String value)118   protected Node representScalar(Tag tag, String value) {
119     return representScalar(tag, value, null);
120   }
121 
representSequence(Tag tag, Iterable<?> sequence, DumperOptions.FlowStyle flowStyle)122   protected Node representSequence(Tag tag, Iterable<?> sequence,
123       DumperOptions.FlowStyle flowStyle) {
124     int size = 10;// default for ArrayList
125     if (sequence instanceof List<?>) {
126       size = ((List<?>) sequence).size();
127     }
128     List<Node> value = new ArrayList<Node>(size);
129     SequenceNode node = new SequenceNode(tag, value, flowStyle);
130     representedObjects.put(objectToRepresent, node);
131     DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
132     for (Object item : sequence) {
133       Node nodeItem = representData(item);
134       if (!(nodeItem instanceof ScalarNode && ((ScalarNode) nodeItem).isPlain())) {
135         bestStyle = FlowStyle.BLOCK;
136       }
137       value.add(nodeItem);
138     }
139     if (flowStyle == FlowStyle.AUTO) {
140       if (defaultFlowStyle != FlowStyle.AUTO) {
141         node.setFlowStyle(defaultFlowStyle);
142       } else {
143         node.setFlowStyle(bestStyle);
144       }
145     }
146     return node;
147   }
148 
representMapping(Tag tag, Map<?, ?> mapping, DumperOptions.FlowStyle flowStyle)149   protected Node representMapping(Tag tag, Map<?, ?> mapping, DumperOptions.FlowStyle flowStyle) {
150     List<NodeTuple> value = new ArrayList<NodeTuple>(mapping.size());
151     MappingNode node = new MappingNode(tag, value, flowStyle);
152     representedObjects.put(objectToRepresent, node);
153     DumperOptions.FlowStyle bestStyle = FlowStyle.FLOW;
154     for (Map.Entry<?, ?> entry : mapping.entrySet()) {
155       Node nodeKey = representData(entry.getKey());
156       Node nodeValue = representData(entry.getValue());
157       if (!(nodeKey instanceof ScalarNode && ((ScalarNode) nodeKey).isPlain())) {
158         bestStyle = FlowStyle.BLOCK;
159       }
160       if (!(nodeValue instanceof ScalarNode && ((ScalarNode) nodeValue).isPlain())) {
161         bestStyle = FlowStyle.BLOCK;
162       }
163       value.add(new NodeTuple(nodeKey, nodeValue));
164     }
165     if (flowStyle == FlowStyle.AUTO) {
166       if (defaultFlowStyle != FlowStyle.AUTO) {
167         node.setFlowStyle(defaultFlowStyle);
168       } else {
169         node.setFlowStyle(bestStyle);
170       }
171     }
172     return node;
173   }
174 
setDefaultScalarStyle(ScalarStyle defaultStyle)175   public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
176     this.defaultScalarStyle = defaultStyle;
177   }
178 
getDefaultScalarStyle()179   public ScalarStyle getDefaultScalarStyle() {
180     if (defaultScalarStyle == null) {
181       return ScalarStyle.PLAIN;
182     }
183     return defaultScalarStyle;
184   }
185 
setDefaultFlowStyle(FlowStyle defaultFlowStyle)186   public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
187     this.defaultFlowStyle = defaultFlowStyle;
188   }
189 
getDefaultFlowStyle()190   public FlowStyle getDefaultFlowStyle() {
191     return this.defaultFlowStyle;
192   }
193 
setPropertyUtils(PropertyUtils propertyUtils)194   public void setPropertyUtils(PropertyUtils propertyUtils) {
195     this.propertyUtils = propertyUtils;
196     this.explicitPropertyUtils = true;
197   }
198 
getPropertyUtils()199   public final PropertyUtils getPropertyUtils() {
200     if (propertyUtils == null) {
201       propertyUtils = new PropertyUtils();
202     }
203     return propertyUtils;
204   }
205 
isExplicitPropertyUtils()206   public final boolean isExplicitPropertyUtils() {
207     return explicitPropertyUtils;
208   }
209 }
210