/*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.internal.xjc.model;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
import com.sun.codemodel.internal.JClass;
import com.sun.codemodel.internal.JCodeModel;
import com.sun.codemodel.internal.JPackage;
import com.sun.istack.internal.Nullable;
import com.sun.tools.internal.xjc.Language;
import com.sun.tools.internal.xjc.model.nav.NClass;
import com.sun.tools.internal.xjc.model.nav.NType;
import com.sun.tools.internal.xjc.outline.Aspect;
import com.sun.tools.internal.xjc.outline.Outline;
import com.sun.tools.internal.xjc.reader.Ring;
import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder;
import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIFactoryMethod;
import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
import com.sun.xml.internal.bind.v2.model.core.Element;
import com.sun.xml.internal.xsom.XSComponent;
import org.xml.sax.Locator;
Mutable ClassInfo
representation.
Schema parsers build these objects.
Author: Kohsuke Kawaguchi
/**
* Mutable {@link ClassInfo} representation.
*
* <p>
* Schema parsers build these objects.
*
* @author Kohsuke Kawaguchi
*/
public final class CClassInfo extends AbstractCElement implements ClassInfo<NType,NClass>, CClassInfoParent, CClass, NClass {
@XmlIDREF
private CClass baseClass;
List of all subclasses, together with nextSibling
. If this class has no sub-class, this field is null. Otherwise, this field points to a sub-class of this class. From there you can enumerate all the sub-classes by using nextSibling
. /**
* List of all subclasses, together with {@link #nextSibling}.
*
* If this class has no sub-class, this field is null. Otherwise,
* this field points to a sub-class of this class. From there you can enumerate
* all the sub-classes by using {@link #nextSibling}.
*/
private CClassInfo firstSubclass;
See Also: - firstSubclass
/**
* @see #firstSubclass
*/
private CClassInfo nextSibling = null;
See Also: - getTypeName()
/**
* @see #getTypeName()
*/
private final QName typeName;
Custom squeezed name
, if any. /**
* Custom {@link #getSqueezedName() squeezed name}, if any.
*/
private /*almost final*/ @Nullable String squeezedName;
If this class also gets XmlRootElement
, the class name. /**
* If this class also gets {@link XmlRootElement}, the class name.
*/
private final @Nullable QName elementName;
private boolean isOrdered = true;
private final List<CPropertyInfo> properties = new ArrayList<CPropertyInfo>();
TODO: revisit this design.
we should at least do a basic encapsulation to avoid careless
mistakes. Maybe we should even differ the javadoc generation
by queueing runners.
/**
* TODO: revisit this design.
* we should at least do a basic encapsulation to avoid careless
* mistakes. Maybe we should even differ the javadoc generation
* by queueing runners.
*/
public String javadoc;
@XmlIDREF
private final CClassInfoParent parent;
short name.
/**
* short name.
*/
public final String shortName;
Optional user-specified implementation override class.
/**
* Optional user-specified implementation override class.
*/
private @Nullable String implClass;
The Model
object to which this bean belongs. /**
* The {@link Model} object to which this bean belongs.
*/
public final Model model;
See Also: - hasAttributeWildcard()
/**
* @see #hasAttributeWildcard()
*/
private boolean hasAttributeWildcard;
public CClassInfo(Model model,JPackage pkg, String shortName, Locator location, QName typeName, QName elementName, XSComponent source, CCustomizations customizations) {
this(model,model.getPackage(pkg),shortName,location,typeName,elementName,source,customizations);
}
public CClassInfo(Model model,CClassInfoParent p, String shortName, Locator location, QName typeName, QName elementName, XSComponent source, CCustomizations customizations) {
super(model,source,location,customizations);
this.model = model;
this.parent = p;
this.shortName = model.allocator.assignClassName(parent,shortName);
this.typeName = typeName;
this.elementName = elementName;
Language schemaLanguage = model.options.getSchemaLanguage();
if ((schemaLanguage != null) &&
(schemaLanguage.equals(Language.XMLSCHEMA) || schemaLanguage.equals(Language.WSDL))) {
BIFactoryMethod factoryMethod = Ring.get(BGMBuilder.class).getBindInfo(source).get(BIFactoryMethod.class);
if(factoryMethod!=null) {
factoryMethod.markAsAcknowledged();
this.squeezedName = factoryMethod.name;
}
}
model.add(this);
}
public CClassInfo(Model model,JCodeModel cm, String fullName, Locator location, QName typeName, QName elementName, XSComponent source, CCustomizations customizations) {
super(model,source,location,customizations);
this.model = model;
int idx = fullName.indexOf('.');
if(idx<0) {
this.parent = model.getPackage(cm.rootPackage());
this.shortName = model.allocator.assignClassName(parent,fullName);
} else {
this.parent = model.getPackage(cm._package(fullName.substring(0,idx)));
this.shortName = model.allocator.assignClassName(parent,fullName.substring(idx+1));
}
this.typeName = typeName;
this.elementName = elementName;
model.add(this);
}
public boolean hasAttributeWildcard() {
return hasAttributeWildcard;
}
public void hasAttributeWildcard(boolean hasAttributeWildcard) {
this.hasAttributeWildcard = hasAttributeWildcard;
}
public boolean hasSubClasses() {
return firstSubclass!=null;
}
Returns true if a new attribute wildcard property needs to be
declared on this class.
/**
* Returns true if a new attribute wildcard property needs to be
* declared on this class.
*/
public boolean declaresAttributeWildcard() {
return hasAttributeWildcard && !inheritsAttributeWildcard();
}
Returns true if this class inherits a wildcard attribute property
from its ancestor classes.
/**
* Returns true if this class inherits a wildcard attribute property
* from its ancestor classes.
*/
public boolean inheritsAttributeWildcard() {
if (getRefBaseClass() != null) {
CClassRef cref = (CClassRef)baseClass;
if (cref.getSchemaComponent().getForeignAttributes().size() > 0) {
return true;
}
} else {
for( CClassInfo c=getBaseClass(); c!=null; c=c.getBaseClass() ) {
if(c.hasAttributeWildcard)
return true;
}
}
return false;
}
public NClass getClazz() {
return this;
}
public CClassInfo getScope() {
return null;
}
@XmlID
public String getName() {
return fullName();
}
Returns the "squeezed name" of this bean token.
The squeezed name of a bean is the concatenation of
the names of its outer classes and itself.
Thus if the bean is "org.acme.foo.Bean", then the squeezed name is "Bean",
if the bean is "org.acme.foo.Outer1.Outer2.Bean", then "Outer1Outer2Bean".
This is used by the code generator
/**
* Returns the "squeezed name" of this bean token.
* <p>
* The squeezed name of a bean is the concatenation of
* the names of its outer classes and itself.
* <p>
* Thus if the bean is "org.acme.foo.Bean", then the squeezed name is "Bean",
* if the bean is "org.acme.foo.Outer1.Outer2.Bean", then "Outer1Outer2Bean".
* <p>
* This is used by the code generator
*/
@XmlElement
public String getSqueezedName() {
if (squeezedName != null) return squeezedName;
return calcSqueezedName.onBean(this);
}
private static final CClassInfoParent.Visitor<String> calcSqueezedName = new Visitor<String>() {
public String onBean(CClassInfo bean) {
return bean.parent.accept(this)+bean.shortName;
}
public String onElement(CElementInfo element) {
return element.parent.accept(this)+element.shortName();
}
public String onPackage(JPackage pkg) {
return "";
}
};
Returns a mutable list.
/**
* Returns a mutable list.
*/
public List<CPropertyInfo> getProperties() {
return properties;
}
public boolean hasValueProperty() {
throw new UnsupportedOperationException();
}
Gets a propery by name.
/**
* Gets a propery by name.
*/
public CPropertyInfo getProperty(String name) {
// TODO: does this method need to be fast?
for( CPropertyInfo p : properties )
if(p.getName(false).equals(name))
return p;
return null;
}
public boolean hasProperties() {
return !getProperties().isEmpty();
}
public boolean isElement() {
return elementName!=null;
}
Guaranteed to return this.
/**
* Guaranteed to return this.
*/
@Deprecated
public CNonElement getInfo() {
return this;
}
public Element<NType,NClass> asElement() {
if(isElement())
return this;
else
return null;
}
public boolean isOrdered() {
return isOrdered;
}
Deprecated:
if you are calling this method directly, you must be doing something wrong.
/**
* @deprecated
* if you are calling this method directly, you must be doing something wrong.
*/
public boolean isFinal() {
return false;
}
public void setOrdered(boolean value) {
isOrdered = value;
}
public QName getElementName() {
return elementName;
}
public QName getTypeName() {
return typeName;
}
public boolean isSimpleType() {
throw new UnsupportedOperationException();
}
Returns the FQCN of this bean.
/**
* Returns the FQCN of this bean.
*/
public String fullName() {
String r = parent.fullName();
if(r.length()==0) return shortName;
else return r+'.'+shortName;
}
public CClassInfoParent parent() {
return parent;
}
public void setUserSpecifiedImplClass(String implClass) {
assert this.implClass==null;
assert implClass!=null;
this.implClass = implClass;
}
public String getUserSpecifiedImplClass() {
return implClass;
}
Adds a new property.
/**
* Adds a new property.
*/
public void addProperty(CPropertyInfo prop) {
if(prop.ref().isEmpty())
// this property isn't contributing anything
// this happens when you try to map an empty sequence to a property
return;
prop.setParent(this);
properties.add(prop);
}
This method accepts both CClassInfo
(which means the base class is also generated), or CClassRef
(which means the base class is already generated and simply referenced.) The latter is treated somewhat special --- from the rest of the model this external base class is invisible. This modeling might need more thoughts to get right. /**
* This method accepts both {@link CClassInfo} (which means the base class
* is also generated), or {@link CClassRef} (which means the base class is
* already generated and simply referenced.)
*
* The latter is treated somewhat special --- from the rest of the model
* this external base class is invisible. This modeling might need more
* thoughts to get right.
*/
public void setBaseClass(CClass base) {
assert baseClass==null;
assert base!=null;
baseClass = base;
assert nextSibling==null;
if (base instanceof CClassInfo) {
CClassInfo realBase = (CClassInfo) base;
this.nextSibling = realBase.firstSubclass;
realBase.firstSubclass = this;
}
}
This inherited version returns null if this class extends from CClassRef
. See Also:
/**
* This inherited version returns null if this class extends from {@link CClassRef}.
*
* @see #getRefBaseClass()
*/
public CClassInfo getBaseClass() {
if (baseClass instanceof CClassInfo) {
return (CClassInfo) baseClass;
} else {
return null;
}
}
public CClassRef getRefBaseClass() {
if (baseClass instanceof CClassRef) {
return (CClassRef) baseClass;
} else {
return null;
}
}
Enumerates all the sub-classes of this class.
/**
* Enumerates all the sub-classes of this class.
*/
public Iterator<CClassInfo> listSubclasses() {
return new Iterator<CClassInfo>() {
CClassInfo cur = firstSubclass;
public boolean hasNext() {
return cur!=null;
}
public CClassInfo next() {
CClassInfo r = cur;
cur = cur.nextSibling;
return r;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public CClassInfo getSubstitutionHead() {
CClassInfo c=getBaseClass();
while(c!=null && !c.isElement())
c=c.getBaseClass();
return c;
}
Interfaces to be implemented.
Lazily constructed.
/**
* Interfaces to be implemented.
* Lazily constructed.
*/
private Set<JClass> _implements = null;
public void _implements(JClass c) {
if(_implements==null)
_implements = new HashSet<JClass>();
_implements.add(c);
}
Constructor declarations. array of Constructor
s. /** Constructor declarations. array of {@link Constructor}s. */
private final List<Constructor> constructors = new ArrayList<Constructor>(1);
Creates a new constructor declaration and adds it. /** Creates a new constructor declaration and adds it. */
public void addConstructor( String... fieldNames ) {
constructors.add(new Constructor(fieldNames));
}
list all constructor declarations. /** list all constructor declarations. */
public Collection<? extends Constructor> getConstructors() {
return constructors;
}
public final <T> T accept(Visitor<T> visitor) {
return visitor.onBean(this);
}
public JPackage getOwnerPackage() {
return parent.getOwnerPackage();
}
public final NClass getType() {
return this;
}
public final JClass toType(Outline o, Aspect aspect) {
switch(aspect) {
case IMPLEMENTATION:
return o.getClazz(this).implRef;
case EXPOSED:
return o.getClazz(this).ref;
default:
throw new IllegalStateException();
}
}
public boolean isBoxedType() {
return false;
}
public String toString() {
return fullName();
}
}