001: /*
002: * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.tools.internal.xjc.model;
027:
028: import java.util.Collection;
029:
030: import javax.xml.bind.annotation.XmlTransient;
031: import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
032: import javax.xml.namespace.QName;
033:
034: import com.sun.codemodel.internal.JClass;
035: import com.sun.codemodel.internal.JJavaName;
036: import com.sun.codemodel.internal.JType;
037: import com.sun.tools.internal.xjc.Plugin;
038: import com.sun.tools.internal.xjc.generator.bean.field.FieldRenderer;
039: import com.sun.tools.internal.xjc.model.nav.NClass;
040: import com.sun.tools.internal.xjc.model.nav.NType;
041: import com.sun.xml.internal.bind.api.impl.NameConverter;
042: import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
043: import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil;
044: import com.sun.xml.internal.xsom.XSComponent;
045:
046: import org.xml.sax.ErrorHandler;
047: import org.xml.sax.Locator;
048:
049: /**
050: * @author Kohsuke Kawaguchi
051: */
052: public abstract class CPropertyInfo implements
053: PropertyInfo<NType, NClass>, CCustomizable {
054:
055: @XmlTransient
056: private CClassInfo parent;
057: private String privateName;
058: private String publicName;
059: private final boolean isCollection;
060:
061: @XmlTransient
062: public final Locator locator;
063:
064: /**
065: * @see #getSchemaComponent()
066: */
067: private final XSComponent source;
068:
069: /**
070: * If the base type of the property is overriden,
071: * this field is set to non-null.
072: */
073: public JType baseType;
074:
075: /**
076: * Javadoc for this property. Must not be null.
077: */
078: public String javadoc = "";
079:
080: /**
081: * Specifies how the field is generated by the backedn.
082: */
083: @XmlJavaTypeAdapter(RuntimeUtil.ToStringAdapter.class)
084: public FieldRenderer realization;
085:
086: /**
087: * If non-null, keeps the default value in Java representation.
088: *
089: * If {@link #isCollection} is true, this field is always null,
090: * for we don't handle default values for a list.
091: */
092: public CDefaultValue defaultValue;
093:
094: private final CCustomizations customizations;
095: /**
096: * @see #getSchemaType()
097: */
098: public QName schemaType;
099:
100: protected CPropertyInfo(String name, boolean collection,
101: XSComponent source, CCustomizations customizations,
102: Locator locator) {
103: this .publicName = name;
104: String n = NameConverter.standard.toVariableName(name);
105: if (!JJavaName.isJavaIdentifier(n))
106: n = '_' + n; // avoid colliding with the reserved names like 'abstract'.
107: this .privateName = n;
108:
109: this .isCollection = collection;
110: this .locator = locator;
111: if (customizations == null)
112: this .customizations = CCustomizations.EMPTY;
113: else
114: this .customizations = customizations;
115: this .source = source;
116: }
117:
118: // called from CClassInfo when added
119: final void setParent(CClassInfo parent) {
120: assert this .parent == null;
121: assert parent != null;
122: this .parent = parent;
123: customizations.setParent(parent.model, this );
124: }
125:
126: public CTypeInfo parent() {
127: return parent;
128: }
129:
130: public Locator getLocator() {
131: return locator;
132: }
133:
134: /**
135: * If this model object is built from XML Schema,
136: * this property returns a schema component from which the model is built.
137: *
138: * @return
139: * null if the model is built from sources other than XML Schema
140: * (such as DTD.)
141: */
142: public final XSComponent getSchemaComponent() {
143: return source;
144: }
145:
146: public abstract CAdapter getAdapter();
147:
148: /**
149: * Name of the property.
150: *
151: * <p>
152: * This method is implemented to follow the contract of
153: * {@link PropertyInfo#getName()}, and therefore it always
154: * returns the name of the annotated field.
155: * <p>
156: * This name is normally not useful for the rest of XJC,
157: * which usually wants to access the "public name" of the property.
158: * A "public name" of the property is a name like "FooBar" which
159: * is used as a seed for generating the accessor methods.
160: * This is the name controlled by the schema customization via users.
161: *
162: * <p>
163: * If the caller is calling this method statically, it's usually
164: * the sign of a mistake. Use {@link #getName(boolean)} method instead,
165: * which forces you to think about which name you want to get.
166: *
167: * @deprecated
168: * marked as deprecated so that we can spot the use of this method.
169: *
170: * @see #getName(boolean)
171: */
172: public String getName() {
173: return getName(false);
174: }
175:
176: /**
177: * Gets the name of the property.
178: *
179: * @param isPublic
180: * if true, this method returns a name like "FooBar", which
181: * should be used as a seed for generating user-visible names
182: * (such as accessors like "getFooBar".)
183: *
184: * <p>
185: * if false, this method returns the "name of the property"
186: * as defined in the j2s side of the spec. This name is usually
187: * something like "fooBar", which often corresponds to the XML
188: * element/attribute name of this property (for taking advantage
189: * of annotation defaulting as much as possible)
190: */
191: public String getName(boolean isPublic) {
192: return isPublic ? publicName : privateName;
193: }
194:
195: /**
196: * Overrides the name of the property.
197: *
198: * This method can be used from {@link Plugin#postProcessModel(Model, ErrorHandler)}.
199: * But the caller should do so with the understanding that this is inherently
200: * dangerous method.
201: */
202: public void setName(boolean isPublic, String newName) {
203: if (isPublic)
204: publicName = newName;
205: else
206: privateName = newName;
207: }
208:
209: public String displayName() {
210: return parent.toString() + '#' + getName(false);
211: }
212:
213: public boolean isCollection() {
214: return isCollection;
215: }
216:
217: public abstract Collection<? extends CTypeInfo> ref();
218:
219: /**
220: * Returns true if this property is "unboxable".
221: *
222: * <p>
223: * In general, a property often has to be capable of representing null
224: * to indicate the absence of the value. This requires properties
225: * to be generated as <tt>@XmlElement Float f</tt>, not as
226: * <tt>@XmlElement float f;</tt>. But this is slow.
227: *
228: * <p>
229: * Fortunately, there are cases where we know that the property can
230: * never legally be absent. When this condition holds we can generate
231: * the optimized "unboxed form".
232: *
233: * <p>
234: * The exact such conditions depend
235: * on the kind of properties, so refer to the implementation code
236: * for the details.
237: *
238: * <p>
239: * This method returns true when the property can be generated
240: * as "unboxed form", false otherwise.
241: *
242: * <p>
243: * When this property is a collection, this method returns true
244: * if items in the collection is unboxable. Obviously, the collection
245: * itself is always a reference type.
246: */
247: public boolean isUnboxable() {
248: Collection<? extends CTypeInfo> ts = ref();
249: if (ts.size() != 1)
250: // if the property is heterogeneous, no way.
251: // ts.size()==0 is a special case that can happen for wildcards.
252: return false;
253:
254: if (baseType != null && (baseType instanceof JClass))
255: return false;
256:
257: CTypeInfo t = ts.iterator().next();
258: // only a primitive type is eligible.
259: return t.getType().isBoxedType();
260: }
261:
262: /**
263: * Returns true if this property needs to represent null
264: * just for the purpose of representing an absence of the property.
265: */
266: public boolean isOptionalPrimitive() {
267: return false;
268: }
269:
270: public CCustomizations getCustomizations() {
271: return customizations;
272: }
273:
274: public QName getSchemaType() {
275: return schemaType;
276: }
277:
278: /**
279: * @deprecated if you are calling this method directly, there's something wrong.
280: */
281: public boolean inlineBinaryData() {
282: return false;
283: }
284:
285: public abstract <V> V accept(CPropertyVisitor<V> visitor);
286: }
|