001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.bind.v2.model.impl;
038:
039: import java.util.Iterator;
040:
041: import javax.xml.bind.annotation.XmlEnum;
042: import javax.xml.bind.annotation.XmlEnumValue;
043: import javax.xml.bind.annotation.XmlRootElement;
044: import javax.xml.namespace.QName;
045:
046: import com.sun.xml.bind.v2.model.annotation.Locatable;
047: import com.sun.xml.bind.v2.model.core.EnumConstant;
048: import com.sun.xml.bind.v2.model.core.EnumLeafInfo;
049: import com.sun.xml.bind.v2.model.core.NonElement;
050: import com.sun.xml.bind.v2.model.core.Element;
051: import com.sun.xml.bind.v2.model.core.ClassInfo;
052: import com.sun.xml.bind.v2.runtime.Location;
053:
054: /**
055: * {@link EnumLeafInfo} implementation.
056: *
057: * @author Kohsuke Kawaguchi
058: */
059: class EnumLeafInfoImpl<T, C, F, M> extends TypeInfoImpl<T, C, F, M>
060: implements EnumLeafInfo<T, C>, Element<T, C>,
061: Iterable<EnumConstantImpl<T, C, F, M>> {
062:
063: /**
064: * The enum class whose information this object represents.
065: */
066: /*package*/final C clazz;
067:
068: NonElement<T, C> baseType;
069:
070: private final T type;
071:
072: /**
073: * Can be null for anonymous types.
074: */
075: private final QName typeName;
076:
077: /**
078: * All the {@link EnumConstantImpl}s are linked in this list.
079: */
080: private EnumConstantImpl<T, C, F, M> firstConstant;
081:
082: /**
083: * If this enum is also bound to an element, that tag name.
084: * Or else null.
085: */
086: private QName elementName;
087:
088: /**
089: * @param clazz
090: * @param type
091: * clazz and type should both point to the enum class
092: * that this {@link EnumLeafInfo} represents.
093: * Because of the type parameterization we have to take them separately.
094: */
095: public EnumLeafInfoImpl(ModelBuilder<T, C, F, M> builder,
096: Locatable upstream, C clazz, T type) {
097: super (builder, upstream);
098: this .clazz = clazz;
099: this .type = type;
100:
101: elementName = parseElementName(clazz);
102:
103: // compute the type name
104: // TODO: I guess it must be allowed for enums to have @XmlElement
105: typeName = parseTypeName(clazz);
106:
107: // locate the base type.
108: // this can be done eagerly because there shouldn't be no cycle.
109: XmlEnum xe = builder.reader.getClassAnnotation(XmlEnum.class,
110: clazz, this );
111: if (xe != null) {
112: T base = builder.reader.getClassValue(xe, "value");
113: baseType = builder.getTypeInfo(base, this );
114: } else {
115: baseType = builder.getTypeInfo(builder.nav
116: .ref(String.class), this );
117: }
118: }
119:
120: /**
121: * Build {@link EnumConstant}s and discover/report any error in it.
122: */
123: protected void calcConstants() {
124: EnumConstantImpl<T, C, F, M> last = null;
125: F[] constants = nav().getEnumConstants(clazz);
126: for (int i = constants.length - 1; i >= 0; i--) {
127: F constant = constants[i];
128: String name = nav().getFieldName(constant);
129: XmlEnumValue xev = builder.reader.getFieldAnnotation(
130: XmlEnumValue.class, constant, this );
131:
132: String literal;
133: if (xev == null)
134: literal = name;
135: else
136: literal = xev.value();
137:
138: last = createEnumConstant(name, literal, constant, last);
139: }
140: this .firstConstant = last;
141: }
142:
143: protected EnumConstantImpl<T, C, F, M> createEnumConstant(
144: String name, String literal, F constant,
145: EnumConstantImpl<T, C, F, M> last) {
146: return new EnumConstantImpl<T, C, F, M>(this , name, literal,
147: last);
148: }
149:
150: public T getType() {
151: return type;
152: }
153:
154: /**
155: * Leaf-type cannot be referenced from IDREF.
156: *
157: * @deprecated
158: * why are you calling a method whose return value is always known?
159: */
160: public final boolean canBeReferencedByIDREF() {
161: return false;
162: }
163:
164: public QName getTypeName() {
165: return typeName;
166: }
167:
168: public C getClazz() {
169: return clazz;
170: }
171:
172: public NonElement<T, C> getBaseType() {
173: return baseType;
174: }
175:
176: public boolean isSimpleType() {
177: return true;
178: }
179:
180: public Location getLocation() {
181: return nav().getClassLocation(clazz);
182: }
183:
184: public Iterable<? extends EnumConstantImpl<T, C, F, M>> getConstants() {
185: if (firstConstant == null)
186: calcConstants();
187: return this ;
188: }
189:
190: public void link() {
191: // make sure we've computed constants
192: getConstants();
193: super .link();
194: }
195:
196: /**
197: * No substitution.
198: *
199: * @deprecated if you are invoking this method directly, there's something wrong.
200: */
201: public Element<T, C> getSubstitutionHead() {
202: return null;
203: }
204:
205: public QName getElementName() {
206: return elementName;
207: }
208:
209: public boolean isElement() {
210: return elementName != null;
211: }
212:
213: public Element<T, C> asElement() {
214: if (isElement())
215: return this ;
216: else
217: return null;
218: }
219:
220: /**
221: * When a bean binds to an element, it's always through {@link XmlRootElement},
222: * so this method always return null.
223: *
224: * @deprecated
225: * you shouldn't be invoking this method on {@link ClassInfoImpl}.
226: */
227: public ClassInfo<T, C> getScope() {
228: return null;
229: }
230:
231: public Iterator<EnumConstantImpl<T, C, F, M>> iterator() {
232: return new Iterator<EnumConstantImpl<T, C, F, M>>() {
233: private EnumConstantImpl<T, C, F, M> next = firstConstant;
234:
235: public boolean hasNext() {
236: return next != null;
237: }
238:
239: public EnumConstantImpl<T, C, F, M> next() {
240: EnumConstantImpl<T, C, F, M> r = next;
241: next = next.next;
242: return r;
243: }
244:
245: public void remove() {
246: throw new UnsupportedOperationException();
247: }
248: };
249: }
250: }
|