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.nodes;
    18
    19  import org.yaml.snakeyaml.error.Mark;
    20
    21  /**
    22   * Base class for all nodes.
    23   * <p>
    24   * The nodes form the node-graph described in the <a
    25   * href="http://yaml.org/spec/1.1/">YAML Specification</a>.
    26   * </p>
    27   * <p>
    28   * While loading, the node graph is usually created by the
    29   * {@link org.yaml.snakeyaml.composer.Composer}, and later transformed into
    30   * application specific Java classes by the classes from the
    31   * {@link org.yaml.snakeyaml.constructor} package.
    32   * </p>
    33   */
    34  public abstract class Node {
    35      private Tag tag;
    36      private Mark startMark;
    37      protected Mark endMark;
    38      private Class<? extends Object> type;
    39      private boolean twoStepsConstruction;
    40      /**
    41       * true when the tag is assigned by the resolver
    42       */
    43      protected boolean resolved;
    44      protected Boolean useClassConstructor;
    45
    46      public Node(Tag tag, Mark startMark, Mark endMark) {
    47          setTag(tag);
    48          this.startMark = startMark;
    49          this.endMark = endMark;
    50          this.type = Object.class;
    51          this.twoStepsConstruction = false;
    52          this.resolved = true;
    53          this.useClassConstructor = null;
    54      }
    55
    56      /**
    57       * Tag of this node.
    58       * <p>
    59       * Every node has a tag assigned. The tag is either local or global.
    60       *
    61       * @return Tag of this node.
    62       */
    63      public Tag getTag() {
    64          return this.tag;
    65      }
    66
    67      public Mark getEndMark() {
    68          return endMark;
    69      }
    70
    71      /**
    72       * For error reporting.
    73       *
    74       * @see class variable 'id' in PyYAML
    75       * @return scalar, sequence, mapping
    76       */
    77      public abstract NodeId getNodeId();
    78
    79      public Mark getStartMark() {
    80          return startMark;
    81      }
    82
    83      public void setTag(Tag tag) {
    84          if (tag == null) {
    85              throw new NullPointerException("tag in a Node is required.");
    86          }
    87          this.tag = tag;
    88      }
    89
    90      /**
    91       * Two Nodes are never equal.
    92       */
    93      @Override
    94      public final boolean equals(Object obj) {
    95          return super.equals(obj);
    96      }
    97
    98      public Class<? extends Object> getType() {
    99          return type;
    100     }
    101
    102     public void setType(Class<? extends Object> type) {
    103         if (!type.isAssignableFrom(this.type)) {
    104             this.type = type;
    105         }
    106     }
    107
    108     public void setTwoStepsConstruction(boolean twoStepsConstruction) {
    109         this.twoStepsConstruction = twoStepsConstruction;
    110     }
    111
    112     /**
    113      * Indicates if this node must be constructed in two steps.
    114      * <p>
    115      * Two-step construction is required whenever a node is a child (direct or
    116      * indirect) of it self. That is, if a recursive structure is build using
    117      * anchors and aliases.
    118      * </p>
    119      * <p>
    120      * Set by {@link org.yaml.snakeyaml.composer.Composer}, used during the
    121      * construction process.
    122      * </p>
    123      * <p>
    124      * Only relevant during loading.
    125      * </p>
    126      *
    127      * @return <code>true</code> if the node is self referenced.
    128      */
    129     public boolean isTwoStepsConstruction() {
    130         return twoStepsConstruction;
    131     }
    132
    133     @Override
    134     public final int hashCode() {
    135         return super.hashCode();
    136     }
    137
    138     public boolean useClassConstructor() {
    139         if (useClassConstructor == null) {
    140             if (isResolved() && !Object.class.equals(type) && !tag.equals(Tag.NULL)) {
    141                 return true;
    142             } else if (tag.isCompatible(getType())) {
    143                 // the tag is compatible with the runtime class
    144                 // the tag will be ignored
    145                 return true;
    146             } else {
    147                 return false;
    148             }
    149         }
    150         return useClassConstructor.booleanValue();
    151     }
    152
    153     public void setUseClassConstructor(Boolean useClassConstructor) {
    154         this.useClassConstructor = useClassConstructor;
    155     }
    156
    157     /**
    158      * Indicates if the tag was added by
    159      * {@link org.yaml.snakeyaml.resolver.Resolver}.
    160      *
    161      * @return <code>true</code> if the tag of this node was resolved</code>
    162      */
    163     public boolean isResolved() {
    164         return resolved;
    165     }
    166 }