ohair@286: /* alanb@368: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.tools.internal.xjc.model; ohair@286: ohair@286: import java.lang.annotation.Annotation; ohair@286: import java.util.Collection; ohair@286: import java.util.Map; ohair@286: ohair@286: import javax.xml.bind.annotation.XmlTransient; ohair@286: import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; ohair@286: import javax.xml.namespace.QName; ohair@286: ohair@286: import com.sun.codemodel.internal.JClass; ohair@286: import com.sun.codemodel.internal.JJavaName; ohair@286: import com.sun.codemodel.internal.JType; ohair@286: import com.sun.tools.internal.xjc.generator.bean.field.FieldRenderer; ohair@286: import com.sun.tools.internal.xjc.model.nav.NClass; ohair@286: import com.sun.tools.internal.xjc.model.nav.NType; alanb@368: import com.sun.tools.internal.xjc.reader.Ring; ohair@286: import com.sun.xml.internal.bind.api.impl.NameConverter; ohair@286: import com.sun.xml.internal.bind.v2.WellKnownNamespace; ohair@286: import com.sun.xml.internal.bind.v2.model.core.PropertyInfo; ohair@286: import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil; ohair@286: import com.sun.xml.internal.xsom.XSComponent; ohair@286: ohair@286: import org.xml.sax.Locator; ohair@286: ohair@286: /** ohair@286: * Model of a property to be generated. ohair@286: * ohair@286: * @author Kohsuke Kawaguchi ohair@286: */ ohair@286: public abstract class CPropertyInfo implements PropertyInfo, CCustomizable { ohair@286: ohair@286: @XmlTransient ohair@286: private CClassInfo parent; ohair@286: private String privateName; ohair@286: private String publicName; ohair@286: private final boolean isCollection; ohair@286: ohair@286: @XmlTransient ohair@286: public final Locator locator; ohair@286: ohair@286: /** ohair@286: * @see #getSchemaComponent() ohair@286: */ ohair@286: private final XSComponent source; ohair@286: ohair@286: /** ohair@286: * If the base type of the property is overriden, ohair@286: * this field is set to non-null. ohair@286: */ ohair@286: public JType baseType; ohair@286: ohair@286: /** ohair@286: * Javadoc for this property. Must not be null. ohair@286: */ ohair@286: public String javadoc=""; ohair@286: ohair@286: /** ohair@286: * Property with {@link @XmlInlineBinaryData}. ohair@286: */ ohair@286: public boolean inlineBinaryData; ohair@286: ohair@286: /** ohair@286: * Specifies how the field is generated by the backend. ohair@286: */ ohair@286: @XmlJavaTypeAdapter(RuntimeUtil.ToStringAdapter.class) ohair@286: public FieldRenderer realization; ohair@286: ohair@286: /** ohair@286: * If non-null, keeps the default value in Java representation. ohair@286: * ohair@286: * If {@link #isCollection} is true, this field is always null, ohair@286: * for we don't handle default values for a list. ohair@286: */ ohair@286: public CDefaultValue defaultValue; ohair@286: ohair@286: private final CCustomizations customizations; ohair@286: ohair@286: protected CPropertyInfo(String name, boolean collection, XSComponent source, ohair@286: CCustomizations customizations, Locator locator) { ohair@286: this.publicName = name; alanb@368: String n = null; alanb@368: alanb@368: Model m = Ring.get(Model.class); alanb@368: if (m != null) { alanb@368: n = m.getNameConverter().toVariableName(name); alanb@368: } else { alanb@368: n = NameConverter.standard.toVariableName(name); alanb@368: } alanb@368: ohair@286: if(!JJavaName.isJavaIdentifier(n)) ohair@286: n = '_'+n; // avoid colliding with the reserved names like 'abstract'. ohair@286: this.privateName = n; ohair@286: ohair@286: this.isCollection = collection; ohair@286: this.locator = locator; ohair@286: if(customizations==null) ohair@286: this.customizations = CCustomizations.EMPTY; ohair@286: else ohair@286: this.customizations = customizations; ohair@286: this.source = source; ohair@286: } ohair@286: ohair@286: // called from CClassInfo when added ohair@286: final void setParent( CClassInfo parent ) { ohair@286: assert this.parent==null; ohair@286: assert parent!=null; ohair@286: this.parent = parent; ohair@286: customizations.setParent(parent.model,this); ohair@286: } ohair@286: ohair@286: public CTypeInfo parent() { ohair@286: return parent; ohair@286: } ohair@286: ohair@286: public Locator getLocator() { ohair@286: return locator; ohair@286: } ohair@286: ohair@286: /** ohair@286: * If this model object is built from XML Schema, ohair@286: * this property returns a schema component from which the model is built. ohair@286: * ohair@286: * @return ohair@286: * null if the model is built from sources other than XML Schema ohair@286: * (such as DTD.) ohair@286: */ ohair@286: public final XSComponent getSchemaComponent() { ohair@286: return source; ohair@286: } ohair@286: ohair@286: public abstract CAdapter getAdapter(); ohair@286: ohair@286: /** ohair@286: * Name of the property. ohair@286: * ohair@286: *

ohair@286: * This method is implemented to follow the contract of ohair@286: * {@link PropertyInfo#getName()}, and therefore it always ohair@286: * returns the name of the annotated field. ohair@286: *

ohair@286: * This name is normally not useful for the rest of XJC, ohair@286: * which usually wants to access the "public name" of the property. ohair@286: * A "public name" of the property is a name like "FooBar" which ohair@286: * is used as a seed for generating the accessor methods. ohair@286: * This is the name controlled by the schema customization via users. ohair@286: * ohair@286: *

ohair@286: * If the caller is calling this method statically, it's usually ohair@286: * the sign of a mistake. Use {@link #getName(boolean)} method instead, ohair@286: * which forces you to think about which name you want to get. ohair@286: * ohair@286: * @deprecated ohair@286: * marked as deprecated so that we can spot the use of this method. ohair@286: * ohair@286: * @see #getName(boolean) ohair@286: */ ohair@286: public String getName() { ohair@286: return getName(false); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Gets the name of the property. ohair@286: * ohair@286: * @param isPublic ohair@286: * if true, this method returns a name like "FooBar", which ohair@286: * should be used as a seed for generating user-visible names ohair@286: * (such as accessors like "getFooBar".) ohair@286: * ohair@286: *

ohair@286: * if false, this method returns the "name of the property" ohair@286: * as defined in the j2s side of the spec. This name is usually ohair@286: * something like "fooBar", which often corresponds to the XML ohair@286: * element/attribute name of this property (for taking advantage ohair@286: * of annotation defaulting as much as possible) ohair@286: */ ohair@286: public String getName(boolean isPublic) { ohair@286: return isPublic?publicName:privateName; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Overrides the name of the property. ohair@286: * ohair@286: * This method can be used from {@link Plugin#postProcessModel(Model, ErrorHandler)}. ohair@286: * But the caller should do so with the understanding that this is inherently ohair@286: * dangerous method. ohair@286: */ ohair@286: public void setName(boolean isPublic, String newName) { ohair@286: if(isPublic) ohair@286: publicName = newName; ohair@286: else ohair@286: privateName = newName; ohair@286: } ohair@286: ohair@286: public String displayName() { ohair@286: return parent.toString()+'#'+getName(false); ohair@286: } ohair@286: ohair@286: public boolean isCollection() { ohair@286: return isCollection; ohair@286: } ohair@286: ohair@286: ohair@286: public abstract Collection ref(); ohair@286: ohair@286: /** ohair@286: * Returns true if this property is "unboxable". ohair@286: * ohair@286: *

ohair@286: * In general, a property often has to be capable of representing null ohair@286: * to indicate the absence of the value. This requires properties ohair@286: * to be generated as @XmlElement Float f, not as ohair@286: * @XmlElement float f;. But this is slow. ohair@286: * ohair@286: *

ohair@286: * Fortunately, there are cases where we know that the property can ohair@286: * never legally be absent. When this condition holds we can generate ohair@286: * the optimized "unboxed form". ohair@286: * ohair@286: *

ohair@286: * The exact such conditions depend ohair@286: * on the kind of properties, so refer to the implementation code ohair@286: * for the details. ohair@286: * ohair@286: *

ohair@286: * This method returns true when the property can be generated ohair@286: * as "unboxed form", false otherwise. ohair@286: * ohair@286: *

ohair@286: * When this property is a collection, this method returns true ohair@286: * if items in the collection is unboxable. Obviously, the collection ohair@286: * itself is always a reference type. ohair@286: */ ohair@286: public boolean isUnboxable() { ohair@286: Collection ts = ref(); ohair@286: if(ts.size()!=1) ohair@286: // if the property is heterogeneous, no way. ohair@286: // ts.size()==0 is a special case that can happen for wildcards. ohair@286: return false; ohair@286: ohair@286: if(baseType!=null && (baseType instanceof JClass)) ohair@286: return false; ohair@286: ohair@286: CTypeInfo t = ts.iterator().next(); ohair@286: // only a primitive type is eligible. ohair@286: return t.getType().isBoxedType(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Returns true if this property needs to represent null ohair@286: * just for the purpose of representing an absence of the property. ohair@286: */ ohair@286: public boolean isOptionalPrimitive() { ohair@286: return false; ohair@286: } ohair@286: ohair@286: public CCustomizations getCustomizations() { ohair@286: return customizations; ohair@286: } ohair@286: ohair@286: public boolean inlineBinaryData() { ohair@286: return inlineBinaryData; ohair@286: } ohair@286: ohair@286: public abstract V accept( CPropertyVisitor visitor ); ohair@286: ohair@286: /** ohair@286: * Checks if the given {@link TypeUse} would need an explicit {@link XmlSchemaType} ohair@286: * annotation with the given type name. ohair@286: */ ohair@286: protected static boolean needsExplicitTypeName(TypeUse type, QName typeName) { ohair@286: if(typeName==null) ohair@286: // this is anonymous type. can't have @XmlSchemaType ohair@286: return false; ohair@286: ohair@286: if(!typeName.getNamespaceURI().equals(WellKnownNamespace.XML_SCHEMA)) ohair@286: // if we put application-defined type name, it will be undefined ohair@286: // by the time we generate a schema. ohair@286: return false; ohair@286: ohair@286: if(type.isCollection()) ohair@286: // there's no built-in binding for a list simple type, ohair@286: // so any collection type always need @XmlSchemaType ohair@286: return true; ohair@286: ohair@286: QName itemType = type.getInfo().getTypeName(); ohair@286: if(itemType==null) ohair@286: // this is somewhat strange case, as it means the bound type is anonymous ohair@286: // but it's eventually derived by a named type and used. ohair@286: // but we can certainly use typeName as @XmlSchemaType value here ohair@286: return true; ohair@286: ohair@286: // if it's the default type name for this item, then no need ohair@286: return !itemType.equals(typeName); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Puts the element names that this property possesses to the map, ohair@286: * so that we can find two properties that own the same element name, ohair@286: * which is an error. ohair@286: * ohair@286: * @return ohair@286: * null if no conflict was found. Otherwise return the QName that has the collision. ohair@286: */ ohair@286: public QName collectElementNames(Map table) { ohair@286: return null; ohair@286: } ohair@286: ohair@286: public final A readAnnotation(Class annotationType) { ohair@286: throw new UnsupportedOperationException(); ohair@286: } ohair@286: ohair@286: public final boolean hasAnnotation(Class annotationType) { ohair@286: throw new UnsupportedOperationException(); ohair@286: } ohair@286: }