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 }