Home | History | Annotate | Download | only in representer
      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 
     63     public Node represent(Object data) {
     64         Node node = representData(data);
     65         representedObjects.clear();
     66         objectToRepresent = null;
     67         return node;
     68     }
     69 
     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 
    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 
    119     protected Node representScalar(Tag tag, String value) {
    120         return representScalar(tag, value, null);
    121     }
    122 
    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 
    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 
    175     public void setDefaultScalarStyle(ScalarStyle defaultStyle) {
    176         this.defaultScalarStyle = defaultStyle.getChar();
    177     }
    178 
    179     public void setDefaultFlowStyle(FlowStyle defaultFlowStyle) {
    180         this.defaultFlowStyle = defaultFlowStyle;
    181     }
    182 
    183     public FlowStyle getDefaultFlowStyle() {
    184         return this.defaultFlowStyle;
    185     }
    186 
    187     public void setPropertyUtils(PropertyUtils propertyUtils) {
    188         this.propertyUtils = propertyUtils;
    189         this.explicitPropertyUtils = true;
    190     }
    191 
    192     public final PropertyUtils getPropertyUtils() {
    193         if (propertyUtils == null) {
    194             propertyUtils = new PropertyUtils();
    195         }
    196         return propertyUtils;
    197     }
    198 
    199     public final boolean isExplicitPropertyUtils() {
    200         return explicitPropertyUtils;
    201     }
    202 }
    203