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 java.math.BigDecimal;
20  import java.math.BigInteger;
21  import java.net.URI;
22  import java.sql.Timestamp;
23  import java.util.Date;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import org.yaml.snakeyaml.error.YAMLException;
30  import org.yaml.snakeyaml.util.UriEncoder;
31  
32  public final class Tag implements Comparable<Tag> {
33      public static final String PREFIX = "tag:yaml.org,2002:";
34      public static final Tag YAML = new Tag(PREFIX + "yaml");
35      public static final Tag VALUE = new Tag(PREFIX + "value");
36      public static final Tag MERGE = new Tag(PREFIX + "merge");
37      public static final Tag SET = new Tag(PREFIX + "set");
38      public static final Tag PAIRS = new Tag(PREFIX + "pairs");
39      public static final Tag OMAP = new Tag(PREFIX + "omap");
40      public static final Tag BINARY = new Tag(PREFIX + "binary");
41      public static final Tag INT = new Tag(PREFIX + "int");
42      public static final Tag FLOAT = new Tag(PREFIX + "float");
43      public static final Tag TIMESTAMP = new Tag(PREFIX + "timestamp");
44      public static final Tag BOOL = new Tag(PREFIX + "bool");
45      public static final Tag NULL = new Tag(PREFIX + "null");
46      public static final Tag STR = new Tag(PREFIX + "str");
47      public static final Tag SEQ = new Tag(PREFIX + "seq");
48      public static final Tag MAP = new Tag(PREFIX + "map");
49      public static final Map<Tag, Set<Class<?>>> COMPATIBILITY_MAP;
50      static {
51          COMPATIBILITY_MAP = new HashMap<Tag, Set<Class<?>>>();
52          Set<Class<?>> floatSet = new HashSet<Class<?>>();
53          floatSet.add(Double.class);
54          floatSet.add(Float.class);
55          floatSet.add(BigDecimal.class);
56          COMPATIBILITY_MAP.put(FLOAT, floatSet);
57          //
58          Set<Class<?>> intSet = new HashSet<Class<?>>();
59          intSet.add(Integer.class);
60          intSet.add(Long.class);
61          intSet.add(BigInteger.class);
62          COMPATIBILITY_MAP.put(INT, intSet);
63          //
64          Set<Class<?>> timestampSet = new HashSet<Class<?>>();
65          timestampSet.add(Date.class);
66          timestampSet.add(java.sql.Date.class);
67          timestampSet.add(Timestamp.class);
68          COMPATIBILITY_MAP.put(TIMESTAMP, timestampSet);
69      }
70  
71      private final String value;
72  
73      public Tag(String tag) {
74          if (tag == null) {
75              throw new NullPointerException("Tag must be provided.");
76          } else if (tag.length() == 0) {
77              throw new IllegalArgumentException("Tag must not be empty.");
78          } else if (tag.trim().length() != tag.length()) {
79              throw new IllegalArgumentException("Tag must not contain leading or trailing spaces.");
80          }
81          this.value = UriEncoder.encode(tag);
82      }
83  
84      public Tag(Class<? extends Object> clazz) {
85          if (clazz == null) {
86              throw new NullPointerException("Class for tag must be provided.");
87          }
88          this.value = Tag.PREFIX + UriEncoder.encode(clazz.getName());
89      }
90  
91      public Tag(URI uri) {
92          if (uri == null) {
93              throw new NullPointerException("URI for tag must be provided.");
94          }
95          this.value = uri.toASCIIString();
96      }
97  
98      public String getValue() {
99          return value;
100     }
101 
102     public boolean startsWith(String prefix) {
103         return value.startsWith(prefix);
104     }
105 
106     public String getClassName() {
107         if (!value.startsWith(Tag.PREFIX)) {
108             throw new YAMLException("Invalid tag: " + value);
109         }
110         return UriEncoder.decode(value.substring(Tag.PREFIX.length()));
111     }
112 
113     public int getLength() {
114         return value.length();
115     }
116 
117     @Override
118     public String toString() {
119         return value;
120     }
121 
122     @Override
123     public boolean equals(Object obj) {
124         if (obj == null) {
125             return false;
126         }
127         if (obj instanceof Tag) {
128             return value.equals(((Tag) obj).getValue());
129         } else if (obj instanceof String) {
130             if (value.equals(obj.toString())) {
131                 // TODO to be removed later (version 2.0?)
132                 System.err.println("Comparing Tag and String is deprecated.");
133                 return true;
134             }
135         }
136         return false;
137     }
138 
139     @Override
140     public int hashCode() {
141         return value.hashCode();
142     }
143 
144     /**
145      * Java has more then 1 class compatible with a language-independent tag
146      * (!!int, !!float, !!timestamp etc)
147      * 
148      * @param clazz
149      *            - Class to check compatibility
150      * @return true when the Class can be represented by this
151      *         language-independent tag
152      */
153     public boolean isCompatible(Class<?> clazz) {
154         Set<Class<?>> set = COMPATIBILITY_MAP.get(this);
155         if (set != null) {
156             return set.contains(clazz);
157         } else {
158             return false;
159         }
160     }
161 
162     /**
163      * Check whether this tag matches the global tag for the Class
164      * 
165      * @param clazz
166      *            - Class to check
167      * @return true when the this tag can be used as a global tag for the Class
168      */
169     public boolean matches(Class<? extends Object> clazz) {
170         return value.equals(Tag.PREFIX + clazz.getName());
171     }
172 
173     public int compareTo(Tag o) {
174         return value.compareTo(o.getValue());
175     }
176 }