Thu, 12 Oct 2017 19:44:07 +0800
merge
1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.bind.v2.model.impl;
28 import java.util.Iterator;
30 import javax.xml.bind.annotation.XmlEnum;
31 import javax.xml.bind.annotation.XmlEnumValue;
32 import javax.xml.bind.annotation.XmlRootElement;
33 import javax.xml.namespace.QName;
35 import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
36 import com.sun.xml.internal.bind.v2.model.core.EnumConstant;
37 import com.sun.xml.internal.bind.v2.model.core.EnumLeafInfo;
38 import com.sun.xml.internal.bind.v2.model.core.NonElement;
39 import com.sun.xml.internal.bind.v2.model.core.Element;
40 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
41 import com.sun.xml.internal.bind.v2.runtime.Location;
42 import java.util.Collection;
43 import javax.xml.bind.annotation.XmlSchemaType;
45 /**
46 * {@link EnumLeafInfo} implementation.
47 *
48 * @author Kohsuke Kawaguchi
49 */
50 class EnumLeafInfoImpl<T,C,F,M> extends TypeInfoImpl<T,C,F,M>
51 implements EnumLeafInfo<T,C>, Element<T,C>, Iterable<EnumConstantImpl<T,C,F,M>> {
53 /**
54 * The enum class whose information this object represents.
55 */
56 /*package*/ final C clazz;
58 NonElement<T,C> baseType;
60 private final T type;
62 /**
63 * Can be null for anonymous types.
64 */
65 private final QName typeName;
67 /**
68 * All the {@link EnumConstantImpl}s are linked in this list.
69 */
70 private EnumConstantImpl<T,C,F,M> firstConstant;
72 /**
73 * If this enum is also bound to an element, that tag name.
74 * Or else null.
75 */
76 private QName elementName;
78 /**
79 * Used to recognize token vs string.
80 */
81 protected boolean tokenStringType;
83 /**
84 * @param clazz
85 * @param type
86 * clazz and type should both point to the enum class
87 * that this {@link EnumLeafInfo} represents.
88 * Because of the type parameterization we have to take them separately.
89 */
90 public EnumLeafInfoImpl(ModelBuilder<T,C,F,M> builder,
91 Locatable upstream, C clazz, T type ) {
92 super(builder,upstream);
93 this.clazz = clazz;
94 this.type = type;
96 elementName = parseElementName(clazz);
98 // compute the type name
99 // TODO: I guess it must be allowed for enums to have @XmlElement
100 typeName = parseTypeName(clazz);
102 // locate the base type.
103 // this can be done eagerly because there shouldn't be no cycle.
104 XmlEnum xe = builder.reader.getClassAnnotation(XmlEnum.class, clazz, this);
105 if(xe!=null) {
106 T base = builder.reader.getClassValue(xe, "value");
107 baseType = builder.getTypeInfo(base,this);
108 } else {
109 baseType = builder.getTypeInfo(builder.nav.ref(String.class),this);
110 }
111 }
113 /**
114 * Build {@link EnumConstant}s and discover/report any error in it.
115 */
116 protected void calcConstants() {
117 EnumConstantImpl<T,C,F,M> last = null;
119 // first check if we represent xs:token derived type
120 Collection<? extends F> fields = nav().getDeclaredFields(clazz);
121 for (F f : fields) {
122 if (nav().isSameType(nav().getFieldType(f), nav().ref(String.class))) {
123 XmlSchemaType schemaTypeAnnotation = builder.reader.getFieldAnnotation(XmlSchemaType.class, f, this);
124 if (schemaTypeAnnotation != null) {
125 if ("token".equals(schemaTypeAnnotation.name())) {
126 tokenStringType = true;
127 break;
128 }
129 };
130 }
131 }
132 F[] constants = nav().getEnumConstants(clazz);
133 for( int i=constants.length-1; i>=0; i-- ) {
134 F constant = constants[i];
135 String name = nav().getFieldName(constant);
136 XmlEnumValue xev = builder.reader.getFieldAnnotation(XmlEnumValue.class, constant, this);
138 String literal;
139 if(xev==null) literal = name;
140 else literal = xev.value();
142 last = createEnumConstant(name,literal,constant,last);
143 }
144 this.firstConstant = last;
145 }
147 protected EnumConstantImpl<T,C,F,M> createEnumConstant(String name, String literal, F constant, EnumConstantImpl<T,C,F,M> last) {
148 return new EnumConstantImpl<T,C,F,M>(this, name, literal, last);
149 }
152 public T getType() {
153 return type;
154 }
156 /**
157 *
158 * @return true if enum is restriction/extension from xs:token type, otherwise false
159 */
160 public boolean isToken() {
161 return tokenStringType;
162 }
164 /**
165 * Leaf-type cannot be referenced from IDREF.
166 *
167 * @deprecated
168 * why are you calling a method whose return value is always known?
169 */
170 public final boolean canBeReferencedByIDREF() {
171 return false;
172 }
174 public QName getTypeName() {
175 return typeName;
176 }
178 public C getClazz() {
179 return clazz;
180 }
182 public NonElement<T,C> getBaseType() {
183 return baseType;
184 }
186 public boolean isSimpleType() {
187 return true;
188 }
190 public Location getLocation() {
191 return nav().getClassLocation(clazz);
192 }
194 public Iterable<? extends EnumConstantImpl<T,C,F,M>> getConstants() {
195 if(firstConstant==null)
196 calcConstants();
197 return this;
198 }
200 @Override
201 public void link() {
202 // make sure we've computed constants
203 getConstants();
204 super.link();
205 }
207 /**
208 * No substitution.
209 *
210 * @deprecated if you are invoking this method directly, there's something wrong.
211 */
212 public Element<T, C> getSubstitutionHead() {
213 return null;
214 }
216 public QName getElementName() {
217 return elementName;
218 }
220 public boolean isElement() {
221 return elementName!=null;
222 }
224 public Element<T,C> asElement() {
225 if(isElement())
226 return this;
227 else
228 return null;
229 }
231 /**
232 * When a bean binds to an element, it's always through {@link XmlRootElement},
233 * so this method always return null.
234 *
235 * @deprecated
236 * you shouldn't be invoking this method on {@link ClassInfoImpl}.
237 */
238 public ClassInfo<T,C> getScope() {
239 return null;
240 }
242 public Iterator<EnumConstantImpl<T,C,F,M>> iterator() {
243 return new Iterator<EnumConstantImpl<T,C,F,M>>() {
244 private EnumConstantImpl<T,C,F,M> next = firstConstant;
245 public boolean hasNext() {
246 return next!=null;
247 }
249 public EnumConstantImpl<T,C,F,M> next() {
250 EnumConstantImpl<T,C,F,M> r = next;
251 next = next.next;
252 return r;
253 }
255 public void remove() {
256 throw new UnsupportedOperationException();
257 }
258 };
259 }
260 }