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