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