/*******************************************************************************
* Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.tools.workbench.mappingsmodel.meta;
import java.io.Serializable;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Vector;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWModel;
import org.eclipse.persistence.tools.workbench.mappingsmodel.MWNominative;
import org.eclipse.persistence.tools.workbench.mappingsmodel.ProblemConstants;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWClassHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle;
import org.eclipse.persistence.tools.workbench.mappingsmodel.handles.MWHandle.NodeReferenceScrubber;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ClassDescription;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClass;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassDescription;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassNotFoundException;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalClassRepository;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalConstructor;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalField;
import org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ExternalMethod;
import org.eclipse.persistence.tools.workbench.utility.ClassTools;
import org.eclipse.persistence.tools.workbench.utility.CollectionTools;
import org.eclipse.persistence.tools.workbench.utility.events.ChangeNotifier;
import org.eclipse.persistence.tools.workbench.utility.events.NullChangeNotifier;
import org.eclipse.persistence.tools.workbench.utility.iterators.ChainIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.CloneIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.CompositeIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.FilteringIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.NullIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.SingleElementIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TransformationIterator;
import org.eclipse.persistence.tools.workbench.utility.iterators.TreeIterator;
import org.eclipse.persistence.tools.workbench.utility.node.Node;
import org.eclipse.persistence.tools.workbench.utility.string.StringTools;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.indirection.IndirectContainer;
import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.eclipse.persistence.mappings.DirectToFieldMapping;
import org.eclipse.persistence.mappings.OneToOneMapping;
import org.eclipse.persistence.mappings.transformers.AttributeTransformer;
import org.eclipse.persistence.mappings.transformers.FieldTransformer;
import org.eclipse.persistence.oxm.XMLDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.internal.codegen.ClassDefinition;
/**
* This class models a Java class or interface.
* See MWClassRepository class comment for lots more information.
*
* @see MWClassRepository
*/
public final class MWClass extends MWModel
implements ClassDescription, MWModifiable, MWNominative {
private volatile String name;
public static final String NAME_PROPERTY = "name";
// declaringType is null unless this type is a "member" type
private MWClassHandle declaringTypeHandle;
public static final String DECLARING_TYPE_PROPERTY = "declaringType";
private MWModifier modifier; // pseudo-final
// convention is to name this flag 'interface', but 'interface' is a Java keyword
private volatile boolean interfaceFlag;
public static final String INTERFACE_PROPERTY = "interface";
private MWClassHandle superclassHandle;
public static final String SUPERCLASS_PROPERTY = "superclass";
public static final String SUPERCLASSES_COLLECTION = "superclasses";
// this will be null if it is not known
private volatile Date lastRefreshTimestamp;
public static final String LAST_REFRESH_TIMESTAMP_PROPERTY = "lastRefreshTimestamp";
private Collection interfaceHandles;
public static final String INTERFACES_COLLECTION = "interfaces";
private NodeReferenceScrubber interfaceScrubber;
private Collection attributes;
public static final String ATTRIBUTES_COLLECTION = "attributes";
private Collection ejb20Attributes;
public static final String EJB20_ATTRIBUTES_COLLECTION = "ejb20Attributes";
// virtual attribute for unknown primary key mapping
private volatile MWClassAttribute unknownPrimaryKeyAttribute;
public static final String UNKNOWN_PK_ATTRIBUTE_PROPERTY = "unknownPKAttribute";
private Collection methods;
public final static String METHODS_COLLECTION = "methods";
private Collection typeHandles;
public static final String TYPES_COLLECTION = "types";
private NodeReferenceScrubber typeScrubber;
// this flag is determined by the class name and cached
private volatile boolean primitive;
// flag core types (primitives, jdk classes, TopLink classes)
// since we don't have visibility to the repository during cloning
// (the backpointer is set during the repository's #postBuild();
// this is private and should not be needed by anything else...
private boolean coreType; // virtually 'final'
// if the type is a "core" type, this flag will be true until a client
// faults in the type's members (attributes, constructors, methods, types)
private volatile boolean partiallyPopulatedCoreType;
// this flag will be true while we are refreshing a core type
// so we can suppress change notifications
private volatile boolean coreTypeRefreshInProgress;
private static PrimitiveWrapperPair[] primitiveWrapperPairs;
private static PrimitiveWrapperPair voidPrimitiveWrapperPair;
public static final String LEGACY_50_STUB_ATTRIBUTE_NAME = "stub";
public static final Boolean LEGACY_50_STUB_NULL_VALUE = Boolean.FALSE;
// ********** constructors **********
/**
* Default constructor - for TopLink use only.
*/
private MWClass() {
super();
}
MWClass(MWClassRepository repository, String name, boolean coreType) {
super(repository);
this.name = name;
this.coreType = coreType;
this.partiallyPopulatedCoreType = coreType;
}
// ********** initialization **********
/**
* initialize transient state
*/
protected void initialize() {
super.initialize();
this.modifier = new MWModifier(this);
// 'primitive' is transient but calculated from 'name', which is persistent
// all types start off as "user" types
this.partiallyPopulatedCoreType = false;
this.coreTypeRefreshInProgress = false;
}
/**
* initialize persistent state
*/
protected void initialize(Node parent) {
super.initialize(parent);
this.declaringTypeHandle = new MWClassHandle(this, this.defaultDeclaringType(), this.buildDeclaringTypeScrubber());
this.interfaceFlag = this.defaultInterfaceFlag();
// if the type is built by hand, this is left null
this.lastRefreshTimestamp = null;
this.interfaceHandles = new Vector();
this.attributes = new Vector();
this.ejb20Attributes = new Vector();
this.unknownPrimaryKeyAttribute = null; // hack for unknown PK attribute
this.methods = new Vector();
this.typeHandles = new Vector();
}
/**
* initialize persistent state that depends on the name;
* this is called by the class repository *after* the type
* has been added, so that circular references can be
* resolved correctly; in particular: String's superclass
* is Object, and Object has a method, toString(), whose
* return time is String; this would fault in an extra version
* of String to the repository, causing identity problems :-(
*/
void initializeNameDependentState() {
// once we have the name, we can set the default values for
// the primitive flag and superclass
this.primitive = this.defaultPrimitiveFlag();
this.superclassHandle = new MWClassHandle(this, this.buildSuperclassScrubber());
this.superclassHandle.setType(this.defaultSuperclass());
}
private MWClass defaultDeclaringType() {
return null;
}
private boolean defaultInterfaceFlag() {
return false;
}
private boolean defaultPrimitiveFlag() {
return CollectionTools.contains(primitiveClassNames(), this.getName());
}
private MWClass defaultSuperclass() {
if (this.requiresSuperclass()) {
return this.objectType();
}
return null;
}
/**
* re-initialize the type to its default settings
*/
public void clear() {
if (this.isCoreType()) {
throw new IllegalStateException();
}
this.setDeclaringType(this.defaultDeclaringType());
this.getModifier().clear();
this.setInterface(this.defaultInterfaceFlag());
this.setSuperclass(this.defaultSuperclass());
this.clearInterfaces();
this.clearAttributes();
this.clearEjb20Attributes();
this.clearMethods();
this.clearTypes();
}
// ********** AbstractNodeModel overrides **********
/**
* suppress change notification when we are refreshing a "core" type;
* this is reasonable because no clients will have ever "seen" an
* unrefreshed "core" type, so they will not need any change notification
* (this also prevents any NPE that may occur when a client starts
* listening to the type and triggers change events while synchronizing
* with the type for the first time)
*/
public ChangeNotifier getChangeNotifier() {
return this.coreTypeRefreshInProgress ?
NullChangeNotifier.instance()
:
super.getChangeNotifier();
}
// ********** accessors **********
// ***** name
public String getName() {
return this.name;
}
public void setName(String name) {
if (name == null) {
throw new NullPointerException();
}
String old = this.name;
this.name = name;
if (this.attributeValueHasChanged(old, name)) {
// synch up the repository before notifying everyone
try {
this.getRepository().typeRenamed(old, name);
} catch (RuntimeException ex) {
this.name = old; // restore the name before re-throwing the exception
throw ex;
}
this.firePropertyChanged(NAME_PROPERTY, old, name);
this.getProject().nodeRenamed(this);
}
}
public String fullName() {
return this.getName();
}
public String shortName() {
return ClassTools.shortNameForClassNamed(this.getName());
}
public String packageName() {
return ClassTools.packageNameForClassNamed(this.getName());
}
public String packageDisplayName() {
return packageDisplayNameForClassNamed(this.getName());
}
// ***** declaringType
/**
* the declaring type can be null
* for normal, top-level classes and interfaces
*/
public MWClass getDeclaringType() {
return this.declaringTypeHandle.getType();
}
/**
* the declaring type can be set to null
* for normal, top-level classes and interfaces
*/
public void setDeclaringType(MWClass declaringType) {
Object old = this.declaringTypeHandle.getType();
this.declaringTypeHandle.setType(declaringType);
this.firePropertyChanged(DECLARING_TYPE_PROPERTY, old, declaringType);
}
// ***** modifier
public MWModifier getModifier() {
return this.modifier;
}
// ***** primitive
public boolean isPrimitive() {
return this.primitive;
}
// ***** interface
public boolean isInterface() {
return this.interfaceFlag;
}
public void setInterface(boolean interfaceFlag) {
if (this.isNonReferenceType() && interfaceFlag) {
throw new IllegalStateException("A primitive cannot be converted to an interface: " + this.getName());
}
boolean old = this.interfaceFlag;
this.interfaceFlag = interfaceFlag;
// if we change the interface flag, we need to reset the superclass
if (old != interfaceFlag) {
this.setSuperclass(this.defaultSuperclass());
}
// fire this after setting the superclass.
// otherwise we hit problems in MWClassRepository.typeChanged(MWClass)
this.firePropertyChanged(INTERFACE_PROPERTY, old, interfaceFlag);
// if we change the interface flag, we need to notify the methods
if (old != interfaceFlag) {
this.notifyMethodsOfAllowedModifiersChange();
}
}
/**
* ...as opposed to an interface
*/
public boolean isClass() {
return ! this.isInterface();
}
// ***** superclass
/**
* the superclass can be null
* (for java.lang.Object, primitives, and interfaces)
*/
public MWClass getSuperclass() {
return this.superclassHandle.getType();
}
/**
* the superclass can be set to null
* (for java.lang.Object, primitives, and interfaces)
*/
public void setSuperclass(MWClass superclass) {
if (this.requiresSuperclass() && (superclass == null)) {
throw new IllegalStateException("Superclass required: " + this);
}
if (this.cannotHaveSuperclass() && (superclass != null)) {
throw new IllegalStateException("Superclass not allowed: " + this);
}
Object old = this.superclassHandle.getType();
this.superclassHandle.setType(superclass);
this.firePropertyChanged(SUPERCLASS_PROPERTY, old, superclass);
if ((old != superclass) && ! this.isCoreType()) {
// notify everyone the hierarchy has changed;
// in particular, descriptors may need to remove mappings etc.
this.superclassesChanged();
this.getRepository().hierarchyChanged(this);
this.getProject().hierarchyChanged(this);
}
}
// ***** lastRefreshTimestamp
/**
* this will be null if it is not known
*/
public Date getLastRefreshTimestamp() {
return this.lastRefreshTimestamp;
}
/**
* PRIVATE - this can only be set internally
*/
private void setLastRefreshTimestamp(Date lastRefreshTimestamp) {
Object old = this.lastRefreshTimestamp;
this.lastRefreshTimestamp = lastRefreshTimestamp;
this.firePropertyChanged(LAST_REFRESH_TIMESTAMP_PROPERTY, old, lastRefreshTimestamp);
}
private Date getLastRefreshTimestampForTopLink() {
Date value = null;
if (getRepository().isPersistLastRefresh()) {
value = this.lastRefreshTimestamp;
}
return value;
}
private void setLastRefreshTimestampForTopLink(Date value) {
this.lastRefreshTimestamp = value;
}
// ***** coreType
/**
* return whether the type is a "core" type:
* - a non-reference class (void, int, double, etc.)
* - a jdk class (java.lang.Object, java.util.Vector, etc.)
* - a TopLink class (Session, ValueHolder, etc.)
* when first constructed, core types are only partially populated
* with their class declaration;
* this method should only be used internally and by the repository...
*/
boolean isCoreType() {
return this.coreType;
}
// ***** interfaces
private Iterator interfaceHandles() {
return new CloneIterator(this.interfaceHandles) {
protected void remove(Object current) {
MWClass.this.removeInterfaceHandle((MWClassHandle) current);
}
public String toString() {
return "MWClass.interfaceHandles()";
}
};
}
void removeInterfaceHandle(MWClassHandle handle) {
this.interfaceHandles.remove(handle);
this.fireItemRemoved(INTERFACES_COLLECTION, handle.getType());
}
public Iterator interfaces() {
return new TransformationIterator(this.interfaceHandles()) {
protected Object transform(Object next) {
return ((MWClassHandle) next).getType();
}
public String toString() {
return "MWClass.interfaces()";
}
};
}
public int interfacesSize() {
return this.interfaceHandles.size();
}
public void addInterface(MWClass type) {
this.interfaceHandles.add(new MWClassHandle(this, type, this.interfaceScrubber()));
this.fireItemAdded(INTERFACES_COLLECTION, type);
}
public void addInterfaces(Collection interfaces) {
this.addInterfaces(interfaces.iterator());
}
public void addInterfaces(Iterator interfaces) {
while (interfaces.hasNext()) {
this.addInterface((MWClass) interfaces.next());
}
}
public void removeInterface(MWClass type) {
for (Iterator stream = this.interfaces(); stream.hasNext(); ) {
if (stream.next() == type) {
stream.remove();
return;
}
}
throw new IllegalArgumentException(type.toString());
}
public void removeInterfaces(Collection interfaces) {
this.removeInterfaces(interfaces.iterator());
}
public void removeInterfaces(Iterator interfaces) {
while (interfaces.hasNext()) {
this.removeInterface((MWClass) interfaces.next());
}
}
public void clearInterfaces() {
// use #interfaceHandles() for minor performance tweak:
for (Iterator stream = this.interfaceHandles(); stream.hasNext(); ) {
stream.next();
stream.remove();
}
}
// ***** attributes
public Iterator attributes() {
this.checkForPartiallyPopulatedCoreType();
return new CloneIterator(this.attributes) {
protected void remove(Object current) {
MWClass.this.removeAttribute((MWClassAttribute) current);
}
public String toString() {
return "MWClass.attributes()";
}
};
}
public int attributesSize() {
this.checkForPartiallyPopulatedCoreType();
return this.attributes.size();
}
public MWClassAttribute addAttribute(String attributeName) {
return this.addAttribute(attributeName, this.objectType());
}
public MWClassAttribute addAttribute(String attributeName, MWClass attributeType) {
return this.addAttribute(attributeName, attributeType, 0);
}
public MWClassAttribute addAttribute(String attributeName, MWClass attributeType, int attributeDimensionality) {
return this.addAttribute(this.buildAttribute(attributeName, attributeType, attributeDimensionality));
}
MWClassAttribute addAttribute(ExternalField externalField) {
return this.addAttribute(new MWClassAttribute(this, externalField));
}
private MWClassAttribute addAttribute(MWClassAttribute attribute) {
this.checkForPartiallyPopulatedCoreType();
MWClassAttribute ejb20Attribute = this.ejb20AttributeNamed(attribute.getName());
if (ejb20Attribute != null) {
// TODO what if ejb 2.0 attribute is in superclass?
this.removeEjb20Attribute(ejb20Attribute);
}
this.addItemToCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION);
return attribute;
}
public void removeAttribute(MWClassAttribute attribute) {
this.checkForPartiallyPopulatedCoreType();
this.removeNodeFromCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION);
}
public void removeAttributes(Collection attrs) {
this.removeAttributes(attrs.iterator());
}
public void removeAttributes(Iterator attrs) {
while (attrs.hasNext()) {
this.removeAttribute((MWClassAttribute) attrs.next());
}
}
public void clearAttributes() {
this.removeAttributes(this.attributes());
}
// ***** ejb20Attributes
public Iterator ejb20Attributes() {
return new CloneIterator(this.ejb20Attributes) {
protected void remove(Object current) {
MWClass.this.removeEjb20Attribute((MWClassAttribute) current);
}
public String toString() {
return "MWClass.ejb20Attributes()";
}
};
}
public Iterator nonEjb20Attributes() {
return this.attributes();
}
public int ejb20AttributesSize() {
return this.ejb20Attributes.size();
}
public MWClassAttribute addEjb20Attribute(String attributeName, MWClass attributeType) {
return this.addEjb20Attribute(attributeName, attributeType, 0);
}
public MWClassAttribute addEjb20Attribute(String attributeName, MWClass attributeType, int attributeDimensionality) {
MWClassAttribute ejbAttribute = this.addEjb20Attribute(this.buildEjb20Attribute(attributeName, attributeType, attributeDimensionality));
ejbAttribute.generateGetAndSetMethods();
return ejbAttribute;
}
private MWClassAttribute addEjb20AttributeInternal(String attributeName, MWClass attributeType, int attributeDimensionality) {
return this.addEjb20Attribute(this.buildEjb20Attribute(attributeName, attributeType, attributeDimensionality));
}
private MWClassAttribute addEjb20Attribute(MWClassAttribute attribute) {
// do not allow an EJB 2.0 attribute to replace a normal Java attribute
if (this.attributeNamed(attribute.getName()) != null) {
// what if attribute is in superclass?
return null;
}
this.addItemToCollection(attribute, this.ejb20Attributes, EJB20_ATTRIBUTES_COLLECTION);
return attribute;
}
public void removeEjb20Attribute(MWClassAttribute attribute) {
this.removeNodeFromCollection(attribute, this.ejb20Attributes, EJB20_ATTRIBUTES_COLLECTION);
}
public void removeEjb20Attributes(Collection attrs) {
this.removeEjb20Attributes(attrs.iterator());
}
public void removeEjb20Attributes(Iterator attrs) {
while (attrs.hasNext()) {
this.removeEjb20Attribute((MWClassAttribute) attrs.next());
}
}
public void clearEjb20Attributes() {
this.removeEjb20Attributes(this.ejb20Attributes());
}
// ***** unknown PK attribute
public boolean usesUnknownPrimaryKeyAttribute() {
return this.unknownPrimaryKeyAttribute != null;
}
public MWClassAttribute getUnknownPrimaryKeyAttribute() {
return this.unknownPrimaryKeyAttribute;
}
// ***** methods
public Iterator methods() {
this.checkForPartiallyPopulatedCoreType();
return new CloneIterator(this.methods) {
protected void remove(Object current) {
MWClass.this.removeMethod((MWMethod) current);
}
public String toString() {
return "MWClass.methods()";
}
};
}
public int methodsSize() {
this.checkForPartiallyPopulatedCoreType();
return this.methods.size();
}
public MWMethod addMethod(String methodName) {
return this.addMethod(this.buildMethod(methodName));
}
public MWMethod addMethod(String methodName, MWClass returnType) {
return this.addMethod(this.buildMethod(methodName, returnType));
}
public MWMethod addMethod(String methodName, MWClass returnType, int dimensionality) {
return this.addMethod(this.buildMethod(methodName, returnType, dimensionality));
}
private MWMethod addMethod(MWMethod method) {
this.checkForPartiallyPopulatedCoreType();
this.methods.add(method);
this.fireItemAdded(METHODS_COLLECTION, method);
return method;
}
public void removeMethod(MWMethod method) {
this.checkForPartiallyPopulatedCoreType();
this.removeNodeFromCollection(method, this.methods, METHODS_COLLECTION);
}
public void removeMethods(Collection methodList) {
this.removeMethods(methodList.iterator());
}
public void removeMethods(Iterator methodStream) {
while (methodStream.hasNext()) {
this.removeMethod((MWMethod) methodStream.next());
}
}
public void clearMethods() {
this.removeMethods(this.methods());
}
// ***** types
private Iterator typeHandles() {
this.checkForPartiallyPopulatedCoreType();
return new CloneIterator(this.typeHandles) {
protected void remove(Object current) {
MWClass.this.removeTypeHandle((MWClassHandle) current);
}
public String toString() {
return "MWClass.typeHandles()";
}
};
}
void removeTypeHandle(MWClassHandle handle) {
// this method is only called from the CloneIterator created in #typeHandles()
// and the scrubber built in #buildTypeScrubber()
// so there is no need to call #checkForPartiallyPopulatedCoreType()
this.typeHandles.remove(handle);
this.fireItemRemoved(TYPES_COLLECTION, handle.getType());
}
public Iterator types() {
return new TransformationIterator(this.typeHandles()) {
protected Object transform(Object next) {
return ((MWClassHandle) next).getType();
}
public String toString() {
return "MWClass.types()";
}
};
}
public int typesSize() {
this.checkForPartiallyPopulatedCoreType();
return this.typeHandles.size();
}
public void addType(MWClass type) {
this.checkForPartiallyPopulatedCoreType();
this.typeHandles.add(new MWClassHandle(this, type, this.typeScrubber()));
this.fireItemAdded(TYPES_COLLECTION, type);
}
public void addTypes(Collection types) {
this.addTypes(types.iterator());
}
public void addTypes(Iterator types) {
while (types.hasNext()) {
this.addType((MWClass) types.next());
}
}
public void removeType(MWClass type) {
for (Iterator stream = this.types(); stream.hasNext(); ) {
if (stream.next() == type) {
stream.remove();
return;
}
}
throw new IllegalArgumentException(type.toString());
}
public void removeTypes(Collection types) {
this.removeTypes(types.iterator());
}
public void removeTypes(Iterator types) {
while (types.hasNext()) {
this.removeType((MWClass) types.next());
}
}
public void clearTypes() {
// use #typeHandles() for minor performance tweak:
for (Iterator stream = this.typeHandles(); stream.hasNext(); ) {
stream.next();
stream.remove();
}
}
// ********** Modifiable implementation **********
public boolean supportsAbstract() {
return true;
}
public boolean canBeSetAbstract() {
return ! this.getModifier().isFinal();
}
public boolean canBeSetFinal() {
return ! this.isAbstract();
}
public boolean supportsInterface() {
return true;
}
public boolean canBeSetInterface() {
return true;
}
public boolean supportsNative() {
return false;
}
public boolean canBeSetNative() {
return false;
}
public boolean canBeSetPackage() {
return true;
}
public boolean canBeSetPrivate() {
return this.isMemberType();
}
public boolean canBeSetProtected() {
return this.isMemberType();
}
public boolean canBeSetPublic() {
return true;
}
public boolean canBeSetStatic() {
return this.isMemberType();
}
/**
* member types are implied to be strictfp...
*/
public boolean isStrict() {
return this.getModifier().isStrict()
|| ((this.getDeclaringType() != null) && this.getDeclaringType().isStrict());
}
public boolean supportsStrict() {
return true;
}
public boolean canBeSetStrict() {
return true;
}
public boolean supportsSynchronized() {
return false;
}
public boolean canBeSetSynchronized() {
return false;
}
public boolean supportsTransient() {
return false;
}
public boolean canBeSetTransient() {
return false;
}
public boolean supportsVolatile() {
return false;
}
public boolean canBeSetVolatile() {
return false;
}
/**
* 'abstract'' and 'final are mutually exclusive
*/
private static final int ALLOWED_MODIFIERS_FLAGS = Modifier.ABSTRACT | Modifier.FINAL;
/**
* if any of these modifiers change for the class, the class's
* methods' "allowed" modifiers may have changed (e.g. if the
* class is no longer 'abstract', none of the class's methods
* can be 'abstract').
*/
private static final int METHOD_ALLOWED_MODIFIERS_FLAGS = Modifier.ABSTRACT | Modifier.FINAL | Modifier.STRICT;
public void modifierChanged(int oldCode, int newCode) {
this.firePropertyChanged(MODIFIER_CODE_PROPERTY, oldCode, newCode);
if (MWModifier.anyFlagsAreDifferent(ALLOWED_MODIFIERS_FLAGS, oldCode, newCode)) {
this.modifier.allowedModifiersChanged();
}
if (MWModifier.anyFlagsAreDifferent(METHOD_ALLOWED_MODIFIERS_FLAGS, oldCode, newCode)) {
this.notifyMethodsOfAllowedModifiersChange();
}
// TODO only "member" classes can be marked 'private', 'protected', or 'static'
}
private void notifyMethodsOfAllowedModifiersChange() {
// no need to fault in the methods for a "core" type
synchronized (this.methods) {
for (Iterator stream = this.methods.iterator(); stream.hasNext(); ) {
((MWMethod) stream.next()).allowedModifiersChanged();
}
}
}
public void accessLevelChanged(String oldValue, String newValue) {
this.firePropertyChanged(MODIFIER_ACCESS_LEVEL_PROPERTY, oldValue, newValue);
}
/**
* return the external class descriptions corresponding to the type;
* any one of these external class descriptions can be used to
* refresh the type;
* @see MWClassRepository#refreshTypeFor(ExternalClassDescription)
*/
public Iterator externalClassDescriptions() {
return this.getRepository().externalClassDescriptionsNamed(this.getName());
}
// ********** queries **********
/**
* @see org.eclipse.persistence.tools.workbench.mappingsmodel.spi.meta.ClassDescription#getAdditionalInfo()
*/
public String getAdditionalInfo() {
return this.getProject().getName();
}
/**
* return whether the type is a member type of another type
*/
public boolean isMemberType() {
return this.getDeclaringType() != null;
}
/**
* return whether the type is a "normal", reference type,
* i.e. it is *not* a primitive or void
*/
public boolean isReferenceType() {
return ! this.isNonReferenceType();
}
/**
* return whether the type is a non-reference type,
* i.e. it is a primitive or void
*/
public boolean isNonReferenceType() {
return this.isPrimitive() || this.isVoid();
}
/**
* interfaces are implied to be abstract...
*/
public boolean isAbstract() {
return this.getModifier().isAbstract()
|| this.isInterface();
}
/**
* return whether the type can be instantiated
*/
public boolean isConcrete() {
return ! this.isAbstract();
}
/**
* return the class's declaring class lineage,
* starting with, and including, itself and
* up to, and including, the top-level class
*/
public Iterator declaringTypeLineage() {
return new ChainIterator(this) {
protected Object nextLink(Object currentLink) {
return ((MWClass) currentLink).getDeclaringType();
}
public String toString() {
return "MWClass.declaringTypeLineage()";
}
};
}
/**
* return whether the class's declaring class lineage,
* as described above, contains the specified type
*/
public boolean declaringTypeLineageContains(MWClass type) {
return CollectionTools.contains(this.declaringTypeLineage(), type);
}
/**
* return the class's declaring classes,
* starting with, and including, its immediate declaring class
* up to, and including, the top-level class
*/
public Iterator declaringTypes() {
MWClass dt = this.getDeclaringType();
if (dt == null) {
return NullIterator.instance();
}
return dt.declaringTypeLineage();
}
/**
* return whether the type is simply a placeholder,
* devoid of any state derived from an "external" class
*/
public boolean isStub() {
if (this.isCoreType()) {
// "core" types are never "stubs"
return false;
}
return this.declaringTypeIsDefaultValue()
&& this.modifier.isDefaultValue()
// ignore the interface flag
&& this.superclassIsDefaultValue()
&& this.interfaceHandles.isEmpty()
&& (this.getComment().length() == 0)
&& this.attributes.isEmpty() // don't fault in 'attributes'
&& this.ejb20Attributes.isEmpty()
&& (this.unknownPrimaryKeyAttribute == null)
&& this.methods.isEmpty() // don't fault in 'methods'
&& this.typeHandles.isEmpty(); // don't fault in 'typeHandles'
}
/**
* return whether the type has been fully populated
* with state derived from an "external" class
*/
public boolean isFullyPopulated() {
return ! this.isStub();
}
/**
* return whether the type and ALL its super-types (superclasses up
* to, and including, java.lang.Object and super-interfaces) are
* fully populated with state derived from their respective "external"
* classes; if everything is fully populated we can legitimately determine
* whether this type is assignable to or from another type whose
* super-types are all fully-populated also
*/
public boolean isFullyTyped() {
for (Iterator stream = this.lineageIncludingInterfaces(); stream.hasNext(); ) {
if (((MWClass) stream.next()).isStub()) {
return false;
}
}
return true;
}
private boolean declaringTypeIsDefaultValue() {
return this.getDeclaringType() == this.defaultDeclaringType();
}
private boolean superclassIsDefaultValue() {
if (this.cannotHaveSuperclass()) {
return this.getSuperclass() == null;
}
// look at the name since we may not have visibility to the class repository yet...
return this.getSuperclass().getName().equals(java.lang.Object.class.getName());
}
/**
* return the class's interfaces, and their interfaces, and so on;
* do NOT include interfaces from the class's superclasses;
* include the class itself if it is an interface
*/
Iterator expandedInterfaces() {
class ExpandedInterfacesTreeIterator extends TreeIterator {
ExpandedInterfacesTreeIterator(Object root) {
super(root);
}
ExpandedInterfacesTreeIterator(Iterator roots) {
super(roots);
}
protected Iterator children(Object next) {
return ((MWClass) next).interfaces();
}
}
return this.isInterface() ?
new ExpandedInterfacesTreeIterator(this)
:
new ExpandedInterfacesTreeIterator(this.interfaces());
}
/**
* return all the interfaces, including those inherited
* (either via superclasses or via super-interfaces);
* include the class itself if it is an interface
*/
public Iterator allInterfaces() {
return new CompositeIterator(
new TransformationIterator(this.lineage()) {
protected Object transform(Object next) {
return ((MWClass) next).expandedInterfaces();
}
public String toString() {
return "MWClass.allInterfaces()";
}
}
);
}
/**
* return all the interfaces, including those inherited
* (either via superclasses or via super-interfaces);
* include the class itself if it is an interface;
* eliminate any duplicates
*/
public Iterator allInterfacesWithoutDuplicates() {
return CollectionTools.set(this.allInterfaces()).iterator();
}
public boolean allInterfacesContains(MWClass interfaceX) {
return CollectionTools.contains(this.allInterfaces(), interfaceX);
}
/**
* return all the attributes, including those inherited
*/
public Iterator allAttributes() {
return new CompositeIterator(
new TransformationIterator(this.lineage()) {
protected Object transform(Object next) {
return ((MWClass) next).attributes();
}
public String toString() {
return "MWClass.allAttributes()";
}
}
);
}
/**
* return the names of the type's attributes;
* duplicate names within a type are not allowed
*/
public Iterator attributeNames() {
return this.attributeNames(this.attributes());
}
/**
* return the names of all the attributes visible to this type;
* duplicate attribute names within a type are not allowed,
* but an attribute name that duplicates an attribute name in
* a superclass *is* allowed (it just might cause problems with debugging)
*/
public Iterator visibleAttributeNames() {
return this.attributeNames(this.visibleAttributes());
}
private Iterator attributeNames(Iterator attrs) {
return new TransformationIterator(attrs) {
protected Object transform(Object next) {
return ((MWClassAttribute) next).getName();
}
public String toString() {
return "MWClass.attributeNames(Iterator)";
}
};
}
public MWClassAttribute attributeNamed(String attributeName) {
return this.attributeNamed(this.attributes(), attributeName);
}
public boolean containsAttributeNamed(String attributeName) {
return this.attributeNamed(attributeName) != null;
}
/**
* include inherited attributes
*/
public MWClassAttribute attributeNamedFromAll(String attributeName) {
return this.attributeNamed(this.allAttributes(), attributeName);
}
/**
* include inherited attributes
*/
public boolean containsAttributeNamedFromAll(String attributeName) {
return this.attributeNamedFromAll(attributeName) != null;
}
/**
* include EJB 2.0 and inherited attributes
*/
public MWClassAttribute attributeNamedFromCombinedAll(String attributeName) {
return this.attributeNamed(this.allCombinedAttributes(), attributeName);
}
/**
* include EJB 2.0 and inherited attributes
*/
public boolean containsAttributeNamedFromCombinedAll(String attributeName) {
return this.attributeNamedFromCombinedAll(attributeName) != null;
}
private MWClassAttribute attributeNamed(Iterator attrs, String attributeName) {
while (attrs.hasNext()) {
MWClassAttribute attribute = (MWClassAttribute) attrs.next();
if (attribute.getName().equals(attributeName)) {
return attribute;
}
}
return null;
}
/**
* as opposed to class variables and constants
*/
public Iterator instanceVariables() {
return this.instanceVariables(this.attributes());
}
/**
* return all the instance variables, including those inherited
*/
public Iterator allInstanceVariables() {
return this.instanceVariables(this.allAttributes());
}
private Iterator instanceVariables(Iterator attrs) {
return new FilteringIterator(attrs) {
protected boolean accept(Object next) {
return ((MWClassAttribute) next).isInstanceVariable();
}
public String toString() {
return "MWClass.instanceVariables(Iterator)";
}
};
}
/**
* return all attributes in type's hierarchy that are visible
* to this type
*/
public Iterator visibleAttributes() {
return this.visibleAttributes(this.allAttributes());
}
private Iterator visibleAttributes(Iterator attrs) {
return new FilteringIterator(attrs) {
protected boolean accept(Object next) {
MWClassAttribute attribute = (MWClassAttribute) next;
if (attribute.getDeclaringType() == MWClass.this) {
return true;
}
if (attribute.getModifier().isPrivate()) {
return false;
}
if (attribute.getModifier().isPublic() || attribute.getModifier().isProtected()) {
return true;
}
return MWClass.this.packageName().equals(attribute.getDeclaringType().packageName());
}
public String toString() {
return "MWClass.visibleAttributes(Iterator)";
}
};
}
/**
* return all the EJB 2.0 attributes, including those inherited
*/
public Iterator allEjb20Attributes() {
return new CompositeIterator(
new TransformationIterator(this.lineage()) {
protected Object transform(Object next) {
return ((MWClass) next).ejb20Attributes();
}
public String toString() {
return "MWClass.allEjb20Attributes()";
}
}
);
}
public MWClassAttribute ejb20AttributeNamed(String attributeName) {
synchronized (this.ejb20Attributes) {
return this.attributeNamed(this.ejb20Attributes.iterator(), attributeName);
}
}
public boolean containsEjb20AttributeNamed(String attributeName) {
return this.ejb20AttributeNamed(attributeName) != null;
}
boolean ejb20AttributesContains(MWClassAttribute attribute) {
return this.ejb20Attributes.contains(attribute);
}
/**
* include inherited EJB 2.0 attributes
*/
public MWClassAttribute ejb20AttributeNamedFromAll(String attributeName) {
return this.attributeNamed(this.allEjb20Attributes(), attributeName);
}
/**
* include inherited EJB 2.0 attributes
*/
public boolean containsEjb20AttributeNamedFromAll(String attributeName) {
return this.ejb20AttributeNamedFromAll(attributeName) != null;
}
/**
* return the combined normal and EJB 2.0 attributes
*/
public Iterator combinedAttributes() {
return new CompositeIterator(this.attributes(), this.ejb20Attributes());
}
/**
* include EJB 2.0 attributes
*/
public MWClassAttribute combinedAttributeNamed(String attributeName) {
return this.attributeNamed(this.combinedAttributes(), attributeName);
}
/**
* include EJB 2.0 attributes
*/
public boolean containsCombinedAttributeNamed(String attributeName) {
return this.combinedAttributeNamed(attributeName) != null;
}
/**
* return all the combined normal and EJB 2.0 attributes,
* including those inherited and the Unknown PK attribute
*/
public Iterator allCombinedAttributes() {
// Have to check to see if the unknownPrimaryKeyAttribute is null... creating a SingleElementIterator with
// a null value here will cause NPE's in attributeNamedFromCombinedAll() when looking up the unknownPrimaryKeyAttribute
return (this.unknownPrimaryKeyAttribute == null) ?
new CompositeIterator(this.allAttributes(), this.allEjb20Attributes())
:
new CompositeIterator(this.allAttributes(), this.allEjb20Attributes(), new SingleElementIterator(this.unknownPrimaryKeyAttribute));
}
/**
* return all the methods, including those inherited
*/
public Iterator allMethods() {
return new CompositeIterator(
new TransformationIterator(this.lineage()) {
protected Object transform(Object next) {
return ((MWClass) next).methods();
}
public String toString() {
return "MWClass.allMethods()";
}
}
);
}
public Iterator constructors() {
return new FilteringIterator(this.methods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isConstructor();
}
public String toString() {
return "MWClass.constructors()";
}
};
}
/**
* static and non-static "regular" methods;
* essentially, any (local) method you can call on an instance of the class
*/
public Iterator nonConstructors() {
return this.nonConstructors(this.methods());
}
/**
* static and non-static "regular" methods, including those inherited;
* essentially, any method you can call on an instance of the class
*/
public Iterator allNonConstructors() {
return this.nonConstructors(this.allMethods());
}
private Iterator nonConstructors(Iterator methodStream) {
return new FilteringIterator(methodStream) {
protected boolean accept(Object next) {
return ! ((MWMethod) next).isConstructor();
}
public String toString() {
return "MWClass.nonConstructors(Iterator)";
}
};
}
public Iterator instanceMethods() {
return this.instanceMethods(this.methods());
}
/**
* return all the instance methods, including those inherited
*/
public Iterator allInstanceMethods() {
return this.instanceMethods(this.allMethods());
}
private Iterator instanceMethods(Iterator methodStream) {
return new FilteringIterator(methodStream) {
protected boolean accept(Object next) {
return ((MWMethod) next).isInstanceMethod();
}
public String toString() {
return "MWClass.instanceMethods(Iterator)";
}
};
}
public Iterator staticMethods() {
return this.staticMethods(this.methods());
}
/**
* return all the static methods, including those inherited
*/
public Iterator allStaticMethods() {
return this.staticMethods(this.allMethods());
}
private Iterator staticMethods(Iterator methodStream) {
return new FilteringIterator(methodStream) {
protected boolean accept(Object next) {
return ((MWMethod) next).isStatic();
}
public String toString() {
return "MWClass.staticMethods(Iterator)";
}
};
}
/**
* any "get" method (zero arguments, return something)
*/
public Iterator candidateTopLinkGetMethods() {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateTopLinkGetMethod();
}
public String toString() {
return "MWClass.candidateTopLinkGetMethods()";
}
};
}
/**
* any "set" method (one argument)
*/
public Iterator candidateTopLinkSetMethods() {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateTopLinkSetMethod();
}
public String toString() {
return "MWClass.candidateTopLinkSetMethods()";
}
};
}
/**
* used by Map container policy
*/
public Iterator candidateMapContainerPolicyKeyMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateMapContainerPolicyKeyMethod();
}
public String toString() {
return "MWClass.candidateMapContainerPolicyKeyMethods()";
}
};
}
/**
* used by inheritance policy
*/
public Iterator candidateClassExtractionMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateClassExtractionMethod();
}
public String toString() {
return "MWClass.candidateClassExtractionMethods()";
}
};
}
/**
* used by clone copy policy
*/
public Iterator candidateCloneMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateCloneMethod();
}
public String toString() {
return "MWClass.candidateCloneMethods()";
}
};
}
/**
* used by events policy
*/
public Iterator candidateDescriptorEventMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateDescriptorEventMethod();
}
public String toString() {
return "MWClass.candidateDescriptorEventMethods()";
}
};
}
/**
* used by instantiation policy
* NB: this should call #methods() not #allMethods()
* If the user wants a static method from a superclass they should choose
* the superclass as the factory class
*/
public Iterator candidateFactoryMethods() {
return new FilteringIterator(this.methods()) { // NOT #allMethods()
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateFactoryMethod();
}
public String toString() {
return "MWClass.candidateFactoryMethods()";
}
};
}
/**
* used by instantiation policy
* NB: this should call #methods() not #allMethods()
* If the user wants a static method from a superclass they should choose
* the superclass as the factory class
*/
public Iterator candidateInstantiationMethods() {
return new FilteringIterator(this.methods()) { // NOT #allMethods()
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateInstantiationMethod();
}
public String toString() {
return "MWClass.candidateInstantiationMethods()";
}
};
}
/**
* used by instantiation policy
*/
public Iterator candidateFactoryInstantiationMethodsFor(final MWClass type) {
return new FilteringIterator(this.allMethods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateFactoryInstantiationMethodFor(type);
}
public String toString() {
return "MWClass.candidateFactoryInstantiationMethodsFor(MWClass)";
}
};
}
/**
* used by after load policy
* NB: this should call #methods() not #allMethods()
* If the user wants a static method from a superclass they should choose
* the superclass as the afterload class
*/
public Iterator candidateDescriptorAfterLoadMethods() {
return new FilteringIterator(this.methods()) { // NOT #allMethods()
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateDescriptorAfterLoadMethod();
}
public String toString() {
return "MWClass.candidateDescriptorAfterLoadMethods()";
}
};
}
/**
* used by transformation mapping
*/
public Iterator candidateAttributeTransformerMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateAttributeTransformerMethod();
}
public String toString() {
return "MWClass.candidateAttributeTransformerMethods()";
}
};
}
/**
* used by transformation mapping
*/
public Iterator candidateFieldTransformerMethods() {
return new FilteringIterator(this.allMethods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isCandidateFieldTransformerMethod();
}
public String toString() {
return "MWClass.candidateFieldTransformerMethods()";
}
};
}
Iterator candidateGetMethodsFor(final MWClassAttribute attribute) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateGetMethodFor(attribute);
}
public String toString() {
return "MWClass.candidateGetMethodsFor(MWClassAttribute)";
}
};
}
Iterator candidateSetMethodsFor(final MWClassAttribute attribute) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateSetMethodFor(attribute);
}
public String toString() {
return "MWClass.candidateSetMethodsFor(MWClassAttribute)";
}
};
}
Iterator candidateGetMethodsFor(final MWClass type) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateGetMethodFor(type);
}
public String toString() {
return "MWClass.candidateGetMethodsFor(MWClass)";
}
};
}
Iterator candidateSetMethodsFor(final MWClass type) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateSetMethodFor(type);
}
public String toString() {
return "MWClass.candidateSetMethodsFor(MWClass)";
}
};
}
Iterator candidateAddMethodsFor(final MWClass itemType) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateAddMethodFor(itemType);
}
public String toString() {
return "MWClass.candidateAddMethodsFor(MWClass)";
}
};
}
Iterator candidateAddMethodsFor(final MWClass keyType, final MWClass itemType) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateAddMethodFor(keyType, itemType);
}
public String toString() {
return "MWClass.candidateAddMethodsFor(MWClass, MWClass)";
}
};
}
Iterator candidateRemoveMethodsFor(final MWClass itemOrKeyType) {
return new FilteringIterator(this.methods()) {
public boolean accept(Object next) {
return ((MWMethod) next).isCandidateRemoveMethodFor(itemOrKeyType);
}
public String toString() {
return "MWClass.candidateRemoveMethodsFor(MWClass)";
}
};
}
/**
* used to refresh EJB 2.0 attributes
*/
private Iterator ejb20GetMethods() {
return new FilteringIterator(this.methods()) {
protected boolean accept(Object next) {
return ((MWMethod) next).isEjb20GetMethod();
}
public String toString() {
return "MWClass.ejb20GetMethods()";
}
};
}
MWMethod ejb20SetMethodFor(MWMethod ejb20GetMethod) {
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.isEjb20SetMethodFor(ejb20GetMethod)) {
return method;
}
}
return null;
}
MWMethod zeroArgumentMethodNamed(String methodName) {
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.hasSignature(methodName)) {
return method;
}
}
return null;
}
MWMethod oneArgumentMethodNamed(String methodName, MWClass type) {
return oneArgumentMethodNamed(methodName, type, 0);
}
MWMethod oneArgumentMethodNamed(String methodName, MWClass type, int dimensionality) {
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.hasSignature(methodName, type, dimensionality)) {
return method;
}
}
return null;
}
MWMethod oneArgumentMethodNamed(String methodName, MWTypeDeclaration declaration) {
return this.oneArgumentMethodNamed(methodName, declaration.getType(), declaration.getDimensionality());
}
MWMethod twoArgumentMethodNamed(String methodName, MWClass type1, MWClass type2) {
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.hasSignature(methodName, type1, 0, type2, 0)) {
return method;
}
}
return null;
}
public MWMethod methodWithSignature(String signature) {
return this.methodWithSignature(this.methods(), signature);
}
/**
* include inherited methods
*/
public MWMethod methodWithSignatureFromAll(String signature) {
return this.methodWithSignature(this.allMethods(), signature);
}
private MWMethod methodWithSignature(Iterator methodStream, String signature) {
while (methodStream.hasNext()) {
MWMethod method = (MWMethod) methodStream.next();
if (method.signature().equals(signature)) {
return method;
}
}
return null;
}
public MWMethod zeroArgumentConstructor() {
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.isZeroArgumentConstructor()) {
return method;
}
}
return null;
}
/**
* used in rules
*/
public boolean hasAccessibleZeroArgumentConstructor() {
if (this.isObject()) {
return true;
}
return (this.zeroArgumentConstructor() != null)
|| this.inheritsAccessibleZeroArgumentConstructor();
}
private boolean inheritsAccessibleZeroArgumentConstructor() {
return ( ! this.constructors().hasNext())
&& (this.getSuperclass() != null)
&& this.getSuperclass().hasAccessibleZeroArgumentConstructor();
}
/**
* Return whether a variable with this type
* can be assigned a value with the specified type.
* For example:
* Object foo = new String(); // this is valid
* String foo = new Object(); // this is invalid
*
* Object.isAssignableFrom(String) => true
*
* We only return true if we are certain of the types'
* assignability.
* See "The Java Language Specification" 5.1.4
* @see java.lang.Class#isAssignableFrom(java.lang.Class)
* @see #mightBeAssignableFrom(MWClass)
*/
public boolean isAssignableFrom(MWClass other) {
if (this == other) {
// "this" and "other" are the same class or interface
return true;
}
if (CollectionTools.contains(other.superclasses(), this)) {
// "other" is a subclass of "this"
return true;
}
if (CollectionTools.contains(other.allInterfaces(), this)) {
// "other" is a subinterface of "this", or "other" implements "this"
return true;
}
if (other.isInterface() && this.isObject()) {
// any interface can be assigned to type Object
return true;
}
return false;
}
/**
* Return whether a variable with this type
* *might* be assigned a value with the specified type.
* If we cannot truly determine assignability
* (i.e. the type is not "fully typed"), we return true.
* We only return true if we are certain of the types'
* assignability.
* @see #isAssignableFrom(MWClass)
*/
public boolean mightBeAssignableFrom(MWClass other) {
return this.isAssignableFrom(other) || ( ! other.isFullyTyped());
}
/**
* Return whether a value with this type can be assigned
* to a variable with the specified type.
* For example:
* Object foo = new String(); // this is valid
* String foo = new Object(); // this is invalid
*
* String.isAssignableTo(Object) => true
*
* See "The Java Language Specification" 5.1.4
* @see java.lang.Class#isAssignableFrom(java.lang.Class)
*/
public boolean isAssignableTo(MWClass other) {
return other.isAssignableFrom(this);
}
/**
* Return whether a value with this type *might* be assigned
* to a variable with the specified type.
* If we cannot truly determine assignability
* (i.e. the type is not "fully typed"), we return true.
* @see #isAssignableTo(MWClass)
*/
public boolean mightBeAssignableTo(MWClass other) {
return other.mightBeAssignableFrom(this);
}
public boolean isBooleanPrimitive() {
return this == this.booleanPrimitiveType();
}
public boolean isCharPrimitive() {
return this == this.charPrimitiveType();
}
public boolean isBytePrimitive() {
return this == this.bytePrimitiveType();
}
public boolean isShortPrimitive() {
return this == this.shortPrimitiveType();
}
public boolean isIntPrimitive() {
return this == this.intPrimitiveType();
}
public boolean isLongPrimitive() {
return this == this.longPrimitiveType();
}
public boolean isFloatPrimitive() {
return this == this.floatPrimitiveType();
}
public boolean isDoublePrimitive() {
return this == this.doublePrimitiveType();
}
public boolean isObject() {
return this == this.objectType();
}
public boolean isSerializable() {
return this == this.serializableType();
}
public boolean isCloneable() {
return this == this.cloneableType();
}
public boolean isAssignableToCollection() {
return this.isAssignableTo(this.collectionType());
}
public boolean mightBeAssignableToCollection() {
return this.mightBeAssignableTo(this.collectionType());
}
public boolean isAssignableToList() {
return this.isAssignableTo(this.listType());
}
public boolean mightBeAssignableToList() {
return this.mightBeAssignableTo(this.listType());
}
public boolean isAssignableToMap() {
return this.isAssignableTo(this.mapType());
}
public boolean mightBeAssignableToMap() {
return this.mightBeAssignableTo(this.mapType());
}
public boolean isAssignableToSet() {
return this.isAssignableTo(this.setType());
}
public boolean mightBeAssignableToSet() {
return this.mightBeAssignableTo(this.setType());
}
public boolean mightBeAssignableToSortedSet() {
return this.mightBeAssignableTo(this.sortedSetType());
}
public boolean mightBeAssignableToComparator() {
return this.mightBeAssignableTo(this.comparatorType());
}
public boolean isAssignableToIndirectContainer() {
return this.isAssignableTo(this.indirectContainerType());
}
public boolean mightBeAssignableToIndirectContainer() {
return this.mightBeAssignableTo(this.indirectContainerType());
}
public boolean isAssignableToAttributeTransformer() {
return this.isAssignableTo(this.attributeTransformerType());
}
public boolean mightBeAssignableToAttributeTransformer() {
return this.mightBeAssignableTo(this.attributeTransformerType());
}
public boolean isAssignableToFieldTransformer() {
return this.isAssignableTo(this.fieldTransformerType());
}
public boolean mightBeAssignableToFieldTransformer() {
return this.mightBeAssignableTo(this.fieldTransformerType());
}
public boolean isContainer() {
return this.isAssignableToCollection()
|| this.isAssignableToMap();
}
public boolean isSubclassOf(MWClass type) {
return CollectionTools.contains(this.superclasses(), type);
}
public boolean isValueHolder() {
return this == this.valueHolderType();
}
public boolean isVoid() {
return this.getName().equals(voidClassName());
}
public boolean isInstantiable() {
return this.isConcrete() && this.isReferenceType();
}
public boolean cannotHaveSuperclass() {
if (this.isNonReferenceType()) {
return true;
}
if (this.isInterface()) {
return true;
}
// we must compare names here, because if we are building java.lang.Object
// then it must not be in the repository yet...
if (this.getName().equals(java.lang.Object.class.getName())) {
return true;
}
return false;
}
public boolean requiresSuperclass() {
return ! this.cannotHaveSuperclass();
}
/**
* return the class's superclass hierarchy,
* starting with, and including, itself and
* up to, and including, java.lang.Object
*/
public Iterator lineage() {
return new ChainIterator(this) {
protected Object nextLink(Object currentLink) {
return ((MWClass) currentLink).getSuperclass();
}
public String toString() {
return "MWClass.lineage()";
}
};
}
/**
* return the class's superclass and interface lineage
* starting with, and including, itself and up to,
* and including, java.lang.Object
*/
public Iterator lineageIncludingInterfaces() {
return new TreeIterator(this) {
protected Iterator children(Object next) {
MWClass type = (MWClass) next;
MWClass superType = type.getSuperclass();
return (superType == null) ?
// we have an interface, a primitive, java.lang.Object, or void
type.interfaces()
:
new CompositeIterator(superType, type.interfaces());
}
public String toString() {
return "MWClass.lineageIncludingInterfaces()";
}
};
}
/**
* return the class's superclass hierarchy,
* starting with, and including, itself and
* up to, and including, the specified superclass
*/
public Iterator lineageTo(final MWClass superclass) {
return new ChainIterator(this) {
protected Object nextLink(Object currentLink) {
return (currentLink == superclass) ? null : ((MWClass) currentLink).getSuperclass();
}
public String toString() {
return "MWClass.lineageTo(MWClass)";
}
};
}
/**
* return whether this type's superclass hierarchy,
* as described above, contains the specified type
*/
public boolean lineageContains(MWClass type) {
return CollectionTools.contains(this.lineage(), type);
}
/**
* return the type's superclasses,
* starting with, and including, its immediate superclass
* up to, and including, java.lang.Object
*/
public Iterator superclasses() {
MWClass sc = this.getSuperclass();
return (sc == null) ? NullIterator.instance() : sc.lineage();
}
/**
* return the immediate [loaded] subclasses of the class
*/
public Iterator subclasses() {
return this.getRepository().subclassesOf(this);
}
/**
* return the immediate [loaded] subclasses of the class,
* all their [loaded] subclasses, and so on
*/
public Iterator allSubclasses() {
return this.getRepository().allSubclassesOf(this);
}
/**
* return the class's entire hierarchy:
* - its superclasses
* - itself
* - all its [loaded] subclasses
*/
public Iterator hierarchy() {
return new CompositeIterator(this.lineage(), this.allSubclasses());
}
private MWClass booleanPrimitiveType() {
return this.typeFor(boolean.class);
}
private MWClass charPrimitiveType() {
return this.typeFor(char.class);
}
private MWClass bytePrimitiveType() {
return this.typeFor(byte.class);
}
private MWClass shortPrimitiveType() {
return this.typeFor(short.class);
}
private MWClass intPrimitiveType() {
return this.typeFor(int.class);
}
private MWClass longPrimitiveType() {
return this.typeFor(long.class);
}
private MWClass floatPrimitiveType() {
return this.typeFor(float.class);
}
private MWClass doublePrimitiveType() {
return this.typeFor(double.class);
}
private MWClass objectType() {
return this.typeFor(Object.class);
}
private MWClass cloneableType() {
return this.typeFor(Cloneable.class);
}
private MWClass serializableType() {
return this.typeFor(Serializable.class);
}
private MWClass collectionType() {
return this.typeFor(Collection.class);
}
private MWClass listType() {
return this.typeFor(List.class);
}
private MWClass mapType() {
return this.typeFor(Map.class);
}
private MWClass setType() {
return this.typeFor(Set.class);
}
private MWClass sortedSetType() {
return this.typeFor(SortedSet.class);
}
private MWClass comparatorType() {
return this.typeFor(Comparator.class);
}
private MWClass indirectContainerType() {
return this.typeFor(IndirectContainer.class);
}
private MWClass attributeTransformerType() {
return this.typeFor(AttributeTransformer.class);
}
private MWClass fieldTransformerType() {
return this.typeFor(FieldTransformer.class);
}
private MWClass valueHolderType() {
return this.typeFor(ValueHolderInterface.class);
}
public boolean typesContains(MWClass type) {
return CollectionTools.contains(this.types(), type);
}
/**
* return a table name for the class
* that is no longer than the specified max length;
* simply convert the short class name to uppercase
* and truncate
*/
public String defaultTableNameWithLength(int maxLength) {
String tableName = this.shortName().toUpperCase();
return (tableName.length() <= maxLength) ?
tableName
:
tableName.substring(0, maxLength);
}
// ********** behavior **********
/**
* containment hierarchy
*/
protected void addChildrenTo(List children) {
super.addChildrenTo(children);
children.add(this.modifier);
children.add(this.declaringTypeHandle);
children.add(this.superclassHandle);
synchronized (this.interfaceHandles) { children.addAll(this.interfaceHandles); }
synchronized (this.typeHandles) { children.addAll(this.typeHandles); } // don't fault in 'typeHandles'
synchronized (this.attributes) { children.addAll(this.attributes); } // don't fault in 'attributes'
synchronized (this.methods) { children.addAll(this.methods); } // don't fault in 'methods'
synchronized (this.ejb20Attributes) { children.addAll(this.ejb20Attributes); }
//this will be null by default, otherwise add it to children
//all of this garbage can be removed once we refactor EJB's out from mwclasses
if (this.unknownPrimaryKeyAttribute != null) {
children.add(this.unknownPrimaryKeyAttribute);
}
}
private NodeReferenceScrubber buildDeclaringTypeScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWClass.this.setDeclaringType(null);
}
public String toString() {
return "MWClass.buildDeclaringTypeScrubber()";
}
};
}
private NodeReferenceScrubber buildSuperclassScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWClass.this.setSuperclass(null);
}
public String toString() {
return "MWClass.buildSuperclassScrubber()";
}
};
}
private NodeReferenceScrubber interfaceScrubber() {
if (this.interfaceScrubber == null) {
this.interfaceScrubber = this.buildInterfaceScrubber();
}
return this.interfaceScrubber;
}
private NodeReferenceScrubber buildInterfaceScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWClass.this.removeInterfaceHandle((MWClassHandle) handle);
}
public String toString() {
return "MWClass.buildInterfaceScrubber()";
}
};
}
private NodeReferenceScrubber typeScrubber() {
if (this.typeScrubber == null) {
this.typeScrubber = this.buildTypeScrubber();
}
return this.typeScrubber;
}
private NodeReferenceScrubber buildTypeScrubber() {
return new NodeReferenceScrubber() {
public void nodeReferenceRemoved(Node node, MWHandle handle) {
MWClass.this.removeTypeHandle((MWClassHandle) handle);
}
public String toString() {
return "MWClass.buildTypeScrubber()";
}
};
}
/**
* Notify the repository that the type has changed.
* @see org.eclipse.persistence.tools.workbench.utility.node.AbstractNodeModel#aspectChanged(java.lang.String)
*/
protected void aspectChanged(String aspectName) {
super.aspectChanged(aspectName);
this.getRepository().typeChanged(this);
}
/**
* If we are dealing with an unsaved new project (one created by the user,
* not read in from XML files), every object is marked dirty and it doesn't
* really matter if a "core" type (and its parent, the class repository) is
* marked dirty. But once the project is saved and everything is marked
* clean, a "core" type can be marked dirty when its members are faulted in
* (@see #checkForPartiallyPopulatedCoreType()). When this happens, we
* don't want the "core" type's parent (the class repository) marked dirty
* because "core" types are never written out to XML files.
*/
protected void markParentBranchDirty() {
if (this.isCoreType()) {
// do nothing - the repository isn't really dirty yet
} else {
super.markParentBranchDirty();
}
}
/**
* reset the "stub" interfaces because they are faulted in during
* #postProjectBuild() as "normal" classes;
* this method should only be called from MWClassRepository#postProjectBuild()
*/
void configureImpliedStubInterfaces() {
for (Iterator stream = this.interfaces(); stream.hasNext(); ) {
((MWClass) stream.next()).configureAsImpliedStubInterface();
}
}
/**
* this type is among another type's list of interfaces; so,
* if this type is a "stub", it is an "implied" interface
*/
private void configureAsImpliedStubInterface() {
if (this.isStub()) {
// Convert a user stub class into a stub interface, since the Java class *probably* is an interface anyway....
// We do not want any change notification(model or event) to occur during reading. This is the reason
// for not calling setInterface(true) directly. Otherwise the model notification hierarchyChanged()
// would be called and other objects postProjectBuild() haven't occurred yet, so NPE's can result.
this.interfaceFlag = true;
this.superclassHandle.setType(null);
}
// if we have a fully-populated class, the user has messed up;
// so just leave it alone...
}
/**
* we will lazily complete the refresh of a "core" type when a client queries for
* any non-initialized state (attributes, constructors, methods, types);
* this method is synchronized because the validation thread can cause a
* "core" type to fault in its non-initialized state and we want to lock the
* type during this loading of state
*/
private synchronized void checkForPartiallyPopulatedCoreType() {
if (this.partiallyPopulatedCoreType) {
this.coreTypeRefreshInProgress = true;
try {
this.refreshMembers();
} catch (ExternalClassNotFoundException ex) {
// if we can't refresh a "core" type, we are in serious trouble...
throw new RuntimeException(this.name, ex);
} finally {
this.coreTypeRefreshInProgress = false;
}
}
}
/**
* refresh the type from the current set of external class descriptions;
* if you would like to force the type to be refreshed from a newly-built
* set of external class descriptions, call
* MWClassRepository#refreshExternalClassDescriptions() first;
* the type will be refreshed with the "default" external class description
* returned by the external class repository
* @see ExternalClassRepository#getExternalClassDescription(String)
*/
public void refresh() throws ExternalClassNotFoundException {
this.refresh(DefaultMWClassRefreshPolicy.instance());
}
public void refresh(MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException {
this.getRepository().refreshType(this, refreshPolicy);
}
/**
* this method can cause a NoClassDefFoundError while
* the external class is introspecting the Java class...
*/
void refreshDeclaration(ExternalClass externalClass) throws ExternalClassNotFoundException {
try {
if ( ! this.getName().equals(externalClass.getName())) {
throw new IllegalArgumentException(this.getName() + " != " + externalClass.getName());
}
this.refreshDeclaringType(externalClass.getDeclaringClass());
this.getModifier().refresh(externalClass.getModifiers());
this.setInterface(externalClass.isInterface());
this.refreshSuperclass(externalClass.getSuperclass());
this.refreshInterfaces(externalClass.getInterfaces());
} catch (Throwable t) {
// TODO catch more specific exceptions, NoClassDefFoundError, ClassNotFoundException, etc
throw new ExternalClassNotFoundException(this.getName(), t);
}
this.setLastRefreshTimestamp(new Date());
}
void refresh(ExternalClass externalClass) throws ExternalClassNotFoundException {
this.refresh(externalClass, DefaultMWClassRefreshPolicy.instance());
}
void refresh(ExternalClass externalClass, MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException {
this.refreshDeclaration(externalClass);
this.refreshMembers(externalClass, refreshPolicy);
}
private void refreshMembers() throws ExternalClassNotFoundException {
this.refreshMembers(DefaultMWClassRefreshPolicy.instance());
}
private void refreshMembers(MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException {
this.getRepository().refreshTypeMembers(this, refreshPolicy);
}
/**
* this method can cause a NoClassDefFoundError while
* the external class is introspecting the Java class...
* e.g. Class.getDeclaredFields() will choke if one of the field types is missing;
* this method is synchronized because the validation thread can cause a
* "core" type to fault in its non-initialized state and we want to lock the
* type during this loading of state
*/
synchronized void refreshMembers(ExternalClass externalClass, MWClassRefreshPolicy refreshPolicy) throws ExternalClassNotFoundException {
// set the flag first so that, if we encounter any problems, we don't try again
this.partiallyPopulatedCoreType = false;
try {
this.refreshAttributes(externalClass.getDeclaredFields(), refreshPolicy);
this.refreshConstructors(externalClass.getDeclaredConstructors());
this.refreshMethods(externalClass.getDeclaredMethods());
this.refreshTypes(externalClass.getDeclaredClasses());
} catch (Throwable t) {
// TODO catch more specific exceptions, NoClassDefFoundError, ClassNotFoundException, etc
throw new ExternalClassNotFoundException(this.getName(), t);
}
refreshPolicy.finalizeRefresh(this);
}
private void refreshDeclaringType(ExternalClassDescription declaringExternalClassDescription) {
if (declaringExternalClassDescription == null) {
this.setDeclaringType(null);
} else {
// do *not* force the declaring class to be populated here
// it will be populated if requested by the user
this.setDeclaringType(this.typeNamed(declaringExternalClassDescription.getName()));
}
}
private void refreshSuperclass(ExternalClassDescription superExternalClassDescription) {
if (superExternalClassDescription == null) {
this.setSuperclass(null);
} else {
// do *not* force the superclass to be populated here
// it will be populated if requested by the user
this.setSuperclass(this.typeNamed(superExternalClassDescription.getName()));
}
}
private void refreshInterfaces(ExternalClassDescription[] externalInterfaces) {
// after we have looped through the external interfaces,
// 'removedInterfaces' will be left with the interfaces that need to be removed
Collection removedInterfaces = CollectionTools.collection(this.interfaces());
for (int i = 0; i < externalInterfaces.length; i++) {
// do *not* force the interface to be populated here
// it will be populated if requested by the user
MWClass mwInterface = this.getRepository().typeNamed(externalInterfaces[i].getName());
mwInterface.configureAsImpliedStubInterface();
if ( ! removedInterfaces.remove(mwInterface)) {
this.addInterface(mwInterface);
}
}
this.removeInterfaces(removedInterfaces);
}
private void refreshAttributes(ExternalField[] externalFields, MWClassRefreshPolicy refreshPolicy) {
refreshPolicy.refreshAttributes(this, externalFields);
}
private void refreshConstructors(ExternalConstructor[] externalConstructors) {
// after we have looped through the Java constructors,
// 'removedConstructors' will be left with the constructors that need to be removed
Collection removedConstructors = CollectionTools.collection(this.constructors());
for (int i = 0; i < externalConstructors.length; i++) {
this.refreshConstructor(externalConstructors[i], removedConstructors);
}
this.removeMethods(removedConstructors);
}
private void refreshConstructor(ExternalConstructor externalConstructor, Collection removedConstructors) {
MWMethod existingConstructor = this.constructorWithSameSignatureAs(externalConstructor);
if (existingConstructor == null) {
// we have a new constructor
this.addMethod(new MWMethod(this, externalConstructor));
} else {
// we need to refresh the existing constructor
existingConstructor.refresh(externalConstructor);
removedConstructors.remove(existingConstructor);
}
}
private MWMethod constructorWithSameSignatureAs(ExternalConstructor externalConstructor) {
for (Iterator stream = this.constructors(); stream.hasNext(); ) {
MWMethod constructor = (MWMethod) stream.next();
if (constructor.hasSameSignatureAs(externalConstructor)) {
return constructor;
}
}
return null;
}
private void refreshMethods(ExternalMethod[] externalMethods) {
// after we have looped through the Java methods,
// 'removedMethods' will be left with the methods that need to be removed
Collection removedMethods = CollectionTools.collection(this.nonConstructors());
for (int i = 0; i < externalMethods.length; i++) {
this.refreshMethod(externalMethods[i], removedMethods);
}
this.removeMethods(removedMethods);
}
private void refreshMethod(ExternalMethod externalMethod, Collection removedMethods) {
if (externalMethod.isSynthetic()) {
return; // we are not interested in compiler-generated methods
}
MWMethod existingMethod = this.methodWithSameSignatureAs(externalMethod);
if (existingMethod == null) {
// we have a new method
this.addMethod(new MWMethod(this, externalMethod));
} else {
// we need to refresh the existing method
existingMethod.refresh(externalMethod);
removedMethods.remove(existingMethod);
}
}
private MWMethod methodWithSameSignatureAs(ExternalMethod externalMethod) {
for (Iterator stream = this.nonConstructors(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
if (method.hasSameSignatureAs(externalMethod)) {
return method;
}
}
return null;
}
private void refreshTypes(ExternalClassDescription[] externalClassDescriptions) {
this.clearTypes(); // clear them out - because we can re-fetch them from the repository
for (int i = 0; i < externalClassDescriptions.length; i++) {
// the classes can be stubs - they don't need to be fully-populated
MWClass mwClass = this.typeNamed(externalClassDescriptions[i].getName());
this.addType(mwClass);
}
}
/**
* synchronize the EJB 2.0 attributes with the abstract getters and
* setters; cascade up through superclasses
*/
public void refreshEjb20Attributes() {
// after we have looped through the get methods,
// 'removedEjb20Attributes' will be left with the attributes that need to be removed
Collection removedEjb20Attributes = CollectionTools.collection(this.ejb20Attributes());
for (Iterator stream = this.ejb20GetMethods(); stream.hasNext(); ) {
MWMethod ejb20GetMethod = (MWMethod) stream.next();
MWMethod ejb20SetMethod = ejb20SetMethodFor(ejb20GetMethod);
if (ejb20SetMethod != null) {
this.refreshEjb20Attribute(ejb20GetMethod, ejb20SetMethod, removedEjb20Attributes);
}
}
this.removeEjb20Attributes(removedEjb20Attributes);
if (this.getSuperclass() != null) {
this.getSuperclass().refreshEjb20Attributes();
}
}
private void refreshEjb20Attribute(MWMethod ejb20GetMethod, MWMethod ejb20SetMethod, Collection removedEjb20Attributes) {
String attrName = StringTools.uncapitalize(ejb20GetMethod.getName().substring(3));
MWClass attrType = ejb20GetMethod.getReturnType();
int attrDim = ejb20GetMethod.getReturnTypeDimensionality();
MWClassAttribute ejb20Attribute = this.ejb20AttributeNamed(attrName);
if (ejb20Attribute == null) {
// we have a new EJB 2.0 attribute
ejb20Attribute = this.addEjb20AttributeInternal(attrName, attrType, attrDim);
} else {
// we need to refresh the existing EJB 2.0 attribute
ejb20Attribute.setType(attrType);
ejb20Attribute.setDimensionality(attrDim);
removedEjb20Attributes.remove(ejb20Attribute);
}
ejb20Attribute.setGetMethod(ejb20GetMethod);
ejb20Attribute.setSetMethod(ejb20SetMethod);
}
public MWMethod addZeroArgumentConstructor() {
MWMethod zeroArgCtor = this.zeroArgumentConstructor();
if (zeroArgCtor != null) {
return zeroArgCtor;
}
return this.addMethod(this.buildZeroArgumentConstructor());
}
// ********** model synchronization support **********
void superclassesChanged() {
this.fireCollectionChanged(SUPERCLASSES_COLLECTION);
}
/**
* don't cascade the removedAttribute() or attributeAdded()
* notifications; we are simply shifting the attribute around
*/
void changeFromEjb20(MWClassAttribute attribute) {
if (this.ejb20Attributes.remove(attribute)) {
this.fireItemRemoved(EJB20_ATTRIBUTES_COLLECTION, attribute);
this.attributes.add(attribute); // don't fault in 'attributes'
this.fireItemAdded(ATTRIBUTES_COLLECTION, attribute);
}
}
/**
* don't cascade the removedAttribute() or attributeAdded()
* notifications; we are simply shifting the attribute around
*/
void changeToEjb20(MWClassAttribute attribute) {
if (this.attributes.remove(attribute)) { // don't fault in 'attributes'
this.fireItemRemoved(ATTRIBUTES_COLLECTION, attribute);
this.ejb20Attributes.add(attribute);
this.fireItemAdded(EJB20_ATTRIBUTES_COLLECTION, attribute);
}
}
// ********** problem handling **********
protected void addProblemsTo(List currentProblems) {
super.addProblemsTo(currentProblems);
// @see #addDescriptorProblemsTo(List)
}
/**
* NB: until we have a visible class repository, these problems
* are added to the descriptor's problems
*/
public void addDescriptorProblemsTo(List currentProblems) {
this.checkSuperclass(currentProblems);
this.checkInterfaces(currentProblems);
this.checkAttributes(currentProblems); // remove this when we get a VCR
}
private void checkSuperclass(List currentProblems) {
MWClass sc = this.getSuperclass();
if ((sc != null) && sc.isInterface()) {
currentProblems.add(this.buildProblem(ProblemConstants.SUPERCLASS_IS_AN_INTERFACE, this.displayStringWithPackage()));
}
}
private void checkInterfaces(List currentProblems) {
for (Iterator stream = this.interfaces(); stream.hasNext(); ) {
MWClass type = (MWClass) stream.next();
if ( ! type.isInterface()) {
currentProblems.add(this.buildProblem(ProblemConstants.IMPLEMENTED_INTERFACE_NOT_AN_INTERFACE, type.displayStringWithPackage()));
}
}
}
private void checkAttributes(List currentProblems) {
for (Iterator stream = this.attributes(); stream.hasNext(); ) {
((MWClassAttribute) stream.next()).addDescriptorProblemsTo(currentProblems);
}
}
// ********** displaying and printing **********
public void toString(StringBuffer sb) {
sb.append(getName());
}
/**
* e.g. "Object"
*/
public String displayString() {
return this.shortName();
}
/**
* e.g. "Object (java.lang)"
*/
public String displayStringWithPackage() {
StringBuffer sb = new StringBuffer(200);
sb.append(this.shortName());
if (this.isReferenceType()) {
sb.append(" (");
sb.append(this.packageDisplayName());
sb.append(')');
}
return sb.toString();
}
void printDefaultReturnValueOn(StringBuffer sb) {
if (this.isVoid()) {
throw new IllegalStateException(this.toString());
}
if (this.isPrimitive()) {
if (this.isBooleanPrimitive()) {
sb.append("false");
} else {
sb.append('0');
}
} else {
sb.append("null");
}
}
/**
* used by Wallace code gen
*/
public ClassDefinition classDefinition(MWClassCodeGenPolicy classCodeGenPolicy) {
if (this.isCoreType()) {
return null;
}
ClassDefinition def = new ClassDefinition();
def.setComment(classCodeGenPolicy.classComment(this));
def.setPackageName(this.packageName());
def.setAccessLevel(this.getModifier().accessLevel());
if (this.isInterface()) {
def.setType(ClassDefinition.INTERFACE_TYPE);
} else {
def.setType(ClassDefinition.CLASS_TYPE);
}
def.setName(this.shortName());
MWClass superclass = this.getSuperclass();
if ((superclass != null) && (superclass != this.objectType())) {
def.setSuperClass(superclass.getName());
}
for (Iterator stream = this.interfaces(); stream.hasNext(); ) {
def.addInterface(((MWClass) stream.next()).getName());
}
for (Iterator stream = this.attributes(); stream.hasNext(); ) {
def.addAttribute(((MWClassAttribute) stream.next()).attributeDefinition());
}
for (Iterator stream = this.methods(); stream.hasNext(); ) {
MWMethod method = (MWMethod) stream.next();
def.addMethod(method.methodDefinition(classCodeGenPolicy.getMethodCodeGenPolicy(method)));
}
// calculate imports after everything else has been added
def.calculateImports();
return def;
}
/**
* return a concrete container type that is assignable to this type
* Map => HashMap
* Set => HashSet
* Collection or List => ArrayList
* if we cannot determine a container type, return null
* used for code gen
*/
MWClass defaultContainerImplementationType() {
if (this.isConcrete() && this.isReferenceType() && this.isContainer()) {
// if we have a concrete "container" type, return it
return this;
}
MWClass container = null;
if (this.isAssignableToMap()) {
container = this.typeFor(HashMap.class);
}
else if (this.isAssignableToSet()) {
container = this.typeFor(HashSet.class);
}
else if (this.isAssignableToCollection()) {
container = this.typeFor(ArrayList.class);
}
if (container == null || this.isAssignableFrom(container)) {
return container;
}
return null;
}
// ********** factory methods **********
private MWClassAttribute buildAttribute(String attributeName, MWClass attributeType, int attributeDimensionality) {
return new MWClassAttribute(this, attributeName, attributeType, attributeDimensionality);
}
private MWClassAttribute buildEjb20Attribute(String attributeName, MWClass attributeType, int attributeDimensionality) {
return this.buildAttribute(attributeName, attributeType, attributeDimensionality);
}
private MWMethod buildMethod(String methodName) {
return new MWMethod(this, methodName);
}
private MWMethod buildMethod(String methodName, MWClass returnType) {
return new MWMethod(this, methodName, returnType);
}
private MWMethod buildMethod(String methodName, MWClass returnType, int dimensionality) {
return new MWMethod(this, methodName, returnType, dimensionality);
}
private MWMethod buildZeroArgumentConstructor() {
return MWMethod.buildZeroArgumentConstructor(this);
}
// ********** TopLink methods **********
public static XMLDescriptor buildDescriptor() {
XMLDescriptor descriptor = new XMLDescriptor();
descriptor.setJavaClass(MWClass.class);
descriptor.setDefaultRootElement("class");
descriptor.addDirectMapping("name", "name/text()");
XMLDirectMapping isInterfaceMapping = (XMLDirectMapping) descriptor.addDirectMapping("interfaceFlag", "is-interface/text()");
isInterfaceMapping.setNullValue(Boolean.FALSE);
XMLDirectMapping modifierMapping = (XMLDirectMapping) descriptor.addDirectMapping("modifier", "getModifierForTopLink", "setModifierForTopLink", "modifier/text()");
modifierMapping.setNullValue(new Integer(0));
XMLCompositeObjectMapping declaringTypeHandleMapping = new XMLCompositeObjectMapping();
declaringTypeHandleMapping.setAttributeName("declaringTypeHandle");
declaringTypeHandleMapping.setSetMethodName("setDeclaringTypeHandleForTopLink");
declaringTypeHandleMapping.setGetMethodName("getDeclaringTypeHandleForTopLink");
declaringTypeHandleMapping.setReferenceClass(MWClassHandle.class);
declaringTypeHandleMapping.setXPath("declaring-type-handle");
descriptor.addMapping(declaringTypeHandleMapping);
XMLCompositeObjectMapping superclassHandleMapping = new XMLCompositeObjectMapping();
superclassHandleMapping.setAttributeName("superclassHandle");
superclassHandleMapping.setReferenceClass(MWClassHandle.class);
superclassHandleMapping.setSetMethodName("setSuperclassHandleForTopLink");
superclassHandleMapping.setGetMethodName("getSuperclassHandleForTopLink");
superclassHandleMapping.setXPath("superclass-handle");
descriptor.addMapping(superclassHandleMapping);
descriptor.addDirectMapping("lastRefreshTimestamp", "getLastRefreshTimestampForTopLink", "setLastRefreshTimestampForTopLink", "last-refresh-timestamp/text()");
XMLCompositeCollectionMapping interfaceHandlesMapping = new XMLCompositeCollectionMapping();
interfaceHandlesMapping.setAttributeName("interfaceHandles");
interfaceHandlesMapping.setSetMethodName("setInterfaceHandlesForTopLink");
interfaceHandlesMapping.setGetMethodName("getInterfaceHandlesForTopLink");
interfaceHandlesMapping.setReferenceClass(MWClassHandle.class);
interfaceHandlesMapping.setXPath("interface-handles/class-handle");
descriptor.addMapping(interfaceHandlesMapping);
XMLCompositeCollectionMapping attributesMapping = new XMLCompositeCollectionMapping();
attributesMapping.setAttributeName("attributes");
attributesMapping.setSetMethodName("setAttributesForTopLink");
attributesMapping.setGetMethodName("getAttributesForTopLink");
attributesMapping.setReferenceClass(MWClassAttribute.class);
attributesMapping.setXPath("attributes/class-attribute");
descriptor.addMapping(attributesMapping);
XMLCompositeCollectionMapping ejb20AttributesMapping = new XMLCompositeCollectionMapping();
ejb20AttributesMapping.setAttributeName("ejb20Attributes");
ejb20AttributesMapping.setSetMethodName("setEjb20AttributesForTopLink");
ejb20AttributesMapping.setGetMethodName("getEjb20AttributesForTopLink");
ejb20AttributesMapping.setReferenceClass(MWClassAttribute.class);
ejb20AttributesMapping.setXPath("ejb-20-attributes/class-attribute");
descriptor.addMapping(ejb20AttributesMapping);
XMLCompositeObjectMapping unknownPrimaryKeyAttributeMapping = new XMLCompositeObjectMapping();
unknownPrimaryKeyAttributeMapping.setAttributeName("unknownPrimaryKeyAttribute");
unknownPrimaryKeyAttributeMapping.setReferenceClass(MWClassAttribute.class);
unknownPrimaryKeyAttributeMapping.setXPath("unknown-primary-key-attribute");
descriptor.addMapping(unknownPrimaryKeyAttributeMapping);
XMLCompositeCollectionMapping methodsMapping = new XMLCompositeCollectionMapping();
methodsMapping.setAttributeName("methods");
methodsMapping.setSetMethodName("setMethodsForTopLink");
methodsMapping.setGetMethodName("getMethodsForTopLink");
methodsMapping.setReferenceClass(MWMethod.class);
methodsMapping.setXPath("methods/method");
descriptor.addMapping(methodsMapping);
XMLCompositeCollectionMapping typeHandlesMapping = new XMLCompositeCollectionMapping();
typeHandlesMapping.setAttributeName("typeHandles");
typeHandlesMapping.setSetMethodName("setTypeHandlesForTopLink");
typeHandlesMapping.setGetMethodName("getTypeHandlesForTopLink");
typeHandlesMapping.setReferenceClass(MWClassHandle.class);
typeHandlesMapping.setXPath("type-handles/class-handle");
descriptor.addMapping(typeHandlesMapping);
XMLDirectMapping coreTypeMapping = (XMLDirectMapping) descriptor.addDirectMapping("coreType", "core-type/text()");
coreTypeMapping.setNullValue(Boolean.FALSE);
return descriptor;
}
/**
* store the modifier as an int
*/
private int getModifierForTopLink() {
return this.modifier.getCode();
}
private void setModifierForTopLink(int code) {
this.modifier.setCodeForTopLink(code);
}
/**
* check for null
*/
private MWClassHandle getDeclaringTypeHandleForTopLink() {
return (this.declaringTypeHandle.getType() == null) ? null : this.declaringTypeHandle;
}
private void setDeclaringTypeHandleForTopLink(MWClassHandle handle) {
NodeReferenceScrubber scrubber = this.buildDeclaringTypeScrubber();
this.declaringTypeHandle = ((handle == null) ? new MWClassHandle(this, scrubber) : handle.setScrubber(scrubber));
}
/**
* check for null
*/
private MWClassHandle getSuperclassHandleForTopLink() {
return (this.superclassHandle.getType() == null) ? null : this.superclassHandle;
}
private void setSuperclassHandleForTopLink(MWClassHandle handle) {
NodeReferenceScrubber scrubber = this.buildSuperclassScrubber();
this.superclassHandle = ((handle == null) ? new MWClassHandle(this, scrubber) : handle.setScrubber(scrubber));
}
/**
* sort the interface handles for TopLink
*/
private Collection getInterfaceHandlesForTopLink() {
synchronized (this.interfaceHandles) {
return new TreeSet(this.interfaceHandles);
}
}
private void setInterfaceHandlesForTopLink(Collection handles) {
for (Iterator stream = handles.iterator(); stream.hasNext(); ) {
((MWClassHandle) stream.next()).setScrubber(this.interfaceScrubber());
}
this.interfaceHandles = handles;
}
/**
* sort the attributes for TopLink
*/
private Collection getAttributesForTopLink() {
// this method will never be called on a "core" type, so we don't need to call #attributes()
synchronized (this.attributes) {
return new TreeSet(this.attributes);
}
}
private void setAttributesForTopLink(Collection attributes) {
this.attributes = attributes;
}
/**
* sort the EJB 2.0 attributes for TopLink
*/
private Collection getEjb20AttributesForTopLink() {
synchronized (this.ejb20Attributes) {
return new TreeSet(this.ejb20Attributes);
}
}
private void setEjb20AttributesForTopLink(Collection ejb20Attributes) {
this.ejb20Attributes = ejb20Attributes;
}
/**
* sort the methods for TopLink
*/
private Collection getMethodsForTopLink() {
// this method will never be called on a "core" type, so we don't need to call #methods()
synchronized (this.methods) {
return new TreeSet(this.methods);
}
}
private void setMethodsForTopLink(Collection methods) {
this.methods = methods;
}
/**
* sort the type handles for TopLink
*/
private Collection getTypeHandlesForTopLink() {
// this method will never be called on a "core" type, so we don't need to call #typeHandles()
synchronized (this.typeHandles) {
return new TreeSet(this.typeHandles);
}
}
private void setTypeHandlesForTopLink(Collection handles) {
for (Iterator stream = handles.iterator(); stream.hasNext(); ) {
MWClassHandle handle = (MWClassHandle) stream.next();
handle.setScrubber(this.typeScrubber());
}
this.typeHandles = handles;
}
/**
* the primitive flag is derived from the class's name
*/
public void postProjectBuild() {
super.postProjectBuild();
this.primitive = this.defaultPrimitiveFlag();
}
// ********** legacy TopLink 6.0 methods **********
public static XMLDescriptor legacy60BuildDescriptor() {
XMLDescriptor descriptor = MWModel.legacy60BuildStandardDescriptor();
descriptor.setJavaClass(MWClass.class);
descriptor.setDefaultRootElement("class");
descriptor.addDirectMapping("name", "legacyGetNameForToplink", "legacySetNameForToplink", "name/text()");
XMLDirectMapping isInterfaceMapping = (XMLDirectMapping) descriptor.addDirectMapping("interfaceFlag", "is-interface/text()");
isInterfaceMapping.setNullValue(Boolean.FALSE);
XMLDirectMapping modifierMapping = (XMLDirectMapping) descriptor.addDirectMapping("modifier", "getModifierForTopLink", "setModifierForTopLink", "modifier/text()");
modifierMapping.setNullValue(new Integer(0));
XMLCompositeObjectMapping declaringTypeHandleMapping = new XMLCompositeObjectMapping();
declaringTypeHandleMapping.setAttributeName("declaringTypeHandle");
declaringTypeHandleMapping.setSetMethodName("setDeclaringTypeHandleForTopLink");
declaringTypeHandleMapping.setGetMethodName("getDeclaringTypeHandleForTopLink");
declaringTypeHandleMapping.setReferenceClass(MWClassHandle.class);
declaringTypeHandleMapping.setXPath("declaring-type-handle");
descriptor.addMapping(declaringTypeHandleMapping);
XMLCompositeObjectMapping superclassHandleMapping = new XMLCompositeObjectMapping();
superclassHandleMapping.setAttributeName("superclassHandle");
superclassHandleMapping.setReferenceClass(MWClassHandle.class);
superclassHandleMapping.setSetMethodName("setSuperclassHandleForTopLink");
superclassHandleMapping.setGetMethodName("getSuperclassHandleForTopLink");
superclassHandleMapping.setXPath("superclass-handle");
descriptor.addMapping(superclassHandleMapping);
descriptor.addDirectMapping("lastRefreshTimestamp", "last-refresh-timestamp/text()");
XMLCompositeCollectionMapping interfaceHandlesMapping = new XMLCompositeCollectionMapping();
interfaceHandlesMapping.setAttributeName("interfaceHandles");
interfaceHandlesMapping.setSetMethodName("setInterfaceHandlesForTopLink");
interfaceHandlesMapping.setGetMethodName("getInterfaceHandlesForTopLink");
interfaceHandlesMapping.setReferenceClass(MWClassHandle.class);
interfaceHandlesMapping.setXPath("interface-handles/class-handle");
descriptor.addMapping(interfaceHandlesMapping);
XMLCompositeCollectionMapping attributesMapping = new XMLCompositeCollectionMapping();
attributesMapping.setAttributeName("attributes");
attributesMapping.setSetMethodName("setAttributesForTopLink");
attributesMapping.setGetMethodName("getAttributesForTopLink");
attributesMapping.setReferenceClass(MWClassAttribute.class);
attributesMapping.setXPath("attributes/class-attribute");
descriptor.addMapping(attributesMapping);
XMLCompositeCollectionMapping ejb20AttributesMapping = new XMLCompositeCollectionMapping();
ejb20AttributesMapping.setAttributeName("ejb20Attributes");
ejb20AttributesMapping.setSetMethodName("setEjb20AttributesForTopLink");
ejb20AttributesMapping.setGetMethodName("getEjb20AttributesForTopLink");
ejb20AttributesMapping.setReferenceClass(MWClassAttribute.class);
ejb20AttributesMapping.setXPath("ejb-20-attributes/class-attribute");
descriptor.addMapping(ejb20AttributesMapping);
XMLCompositeObjectMapping unknownPrimaryKeyAttributeMapping = new XMLCompositeObjectMapping();
unknownPrimaryKeyAttributeMapping.setAttributeName("unknownPrimaryKeyAttribute");
unknownPrimaryKeyAttributeMapping.setReferenceClass(MWClassAttribute.class);
unknownPrimaryKeyAttributeMapping.setXPath("unknown-primary-key-attribute");
descriptor.addMapping(unknownPrimaryKeyAttributeMapping);
XMLCompositeCollectionMapping methodsMapping = new XMLCompositeCollectionMapping();
methodsMapping.setAttributeName("methods");
methodsMapping.setSetMethodName("setMethodsForTopLink");
methodsMapping.setGetMethodName("getMethodsForTopLink");
methodsMapping.setReferenceClass(MWMethod.class);
methodsMapping.setXPath("methods/method");
descriptor.addMapping(methodsMapping);
XMLCompositeCollectionMapping typeHandlesMapping = new XMLCompositeCollectionMapping();
typeHandlesMapping.setAttributeName("typeHandles");
typeHandlesMapping.setSetMethodName("setTypeHandlesForTopLink");
typeHandlesMapping.setGetMethodName("getTypeHandlesForTopLink");
typeHandlesMapping.setReferenceClass(MWClassHandle.class);
typeHandlesMapping.setXPath("type-handles/class-handle");
descriptor.addMapping(typeHandlesMapping);
XMLDirectMapping coreTypeMapping = (XMLDirectMapping) descriptor.addDirectMapping("coreType", "core-type/text()");
coreTypeMapping.setNullValue(Boolean.FALSE);
return descriptor;
}
/**
* legacy projects may contain references to org.eclipse.persistence.publicinterface.Descriptor which has been removed.
*/
private String legacyGetNameForToplink() {
return this.name;
}
private void legacySetNameForToplink(String legacyName) {
this.name = MWModel.legacyReplaceToplinkDeprecatedClassReferences(legacyName);
}
// ********** static methods **********
/**
* if the specified class is in the default package, we
* will return "(default package)"
*/
public static String packageDisplayNameForClassNamed(String className) {
if (nonReferenceClassNamesContains(className)) {
return "";
}
int lastPeriod = className.lastIndexOf('.');
if (lastPeriod == -1) {
return "(default package)";
}
return className.substring(0, lastPeriod);
}
/**
* if the specified class is in the default package, we
* will return "(default package)"
*/
public static String packageDisplayNameFor(Class javaClass) {
return packageDisplayNameForClassNamed(javaClass.getName());
}
private static PrimitiveWrapperPair[] buildPrimitiveWrapperPairs() {
PrimitiveWrapperPair[] result = new PrimitiveWrapperPair[8];
result[0] = new PrimitiveWrapperPair(boolean.class, java.lang.Boolean.class);
result[1] = new PrimitiveWrapperPair(char.class, java.lang.Character.class);
result[2] = new PrimitiveWrapperPair(byte.class, java.lang.Byte.class);
result[3] = new PrimitiveWrapperPair(short.class, java.lang.Short.class);
result[4] = new PrimitiveWrapperPair(int.class, java.lang.Integer.class);
result[5] = new PrimitiveWrapperPair(long.class, java.lang.Long.class);
result[6] = new PrimitiveWrapperPair(float.class, java.lang.Float.class);
result[7] = new PrimitiveWrapperPair(double.class, java.lang.Double.class);
return result;
}
private static synchronized PrimitiveWrapperPair[] getPrimitiveWrapperPairs() {
if (primitiveWrapperPairs == null) {
primitiveWrapperPairs = buildPrimitiveWrapperPairs();
}
return primitiveWrapperPairs;
}
private static Iterator primitiveWrapperPairs() {
return CollectionTools.iterator(getPrimitiveWrapperPairs());
}
private static Iterator primitiveClasses(Iterator pairs) {
return new TransformationIterator(pairs) {
protected Object transform(Object next) {
return ((PrimitiveWrapperPair) next).getPrimitiveClass();
}
public String toString() {
return "MWClass.primitiveClasses(Iterator)";
}
};
}
private static Iterator primitiveClassNames(Iterator pairs) {
return new TransformationIterator(pairs) {
protected Object transform(Object next) {
return ((PrimitiveWrapperPair) next).primitiveClassName();
}
public String toString() {
return "MWClass.primitiveClassNames(Iterator)";
}
};
}
private static Iterator wrapperClasses(Iterator pairs) {
return new TransformationIterator(pairs) {
protected Object transform(Object next) {
return ((PrimitiveWrapperPair) next).getWrapperClass();
}
public String toString() {
return "MWClass.wrapperClasses(Iterator)";
}
};
}
/**
* return the Java primitive class with the specified name
* (e.g. int, char); does *not* include void;
* if the name is not for a primitive, return null
*/
public static Class primitiveClassNamed(String className) {
PrimitiveWrapperPair[] pairs = getPrimitiveWrapperPairs();
int len = pairs.length;
for (int i = 0; i < len; i++) {
if (pairs[i].primitiveClassName().equals(className)) {
return pairs[i].getPrimitiveClass();
}
}
return null;
}
/**
* return the Java primitive classes
* (e.g. int, char); does *not* include void
*/
public static Iterator primitiveClasses() {
return primitiveClasses(primitiveWrapperPairs());
}
/**
* return the Java primitive wrapper classes
* (e.g. java.lang.Integer, java.lang.Character);
* does *not* include java.lang.Void
*/
public static Iterator primitiveWrapperClasses() {
return wrapperClasses(primitiveWrapperPairs());
}
/**
* return the names of the Java primitive classes
* (e.g. "int", "char"); does *not* include "void"
*/
public static Iterator primitiveClassNames() {
return primitiveClassNames(primitiveWrapperPairs());
}
private static synchronized PrimitiveWrapperPair getVoidPrimitiveWrapperPair() {
if (voidPrimitiveWrapperPair == null) {
voidPrimitiveWrapperPair = new PrimitiveWrapperPair(void.class, java.lang.Void.class);
}
return voidPrimitiveWrapperPair;
}
public static Class voidClass() {
return getVoidPrimitiveWrapperPair().getPrimitiveClass();
}
public static Class voidWrapperClass() {
return getVoidPrimitiveWrapperPair().getWrapperClass();
}
public static String voidClassName() {
return getVoidPrimitiveWrapperPair().primitiveClassName();
}
private static Iterator nonReferencePrimitiveWrapperPairs() {
return new CompositeIterator(
CollectionTools.singletonIterator(getVoidPrimitiveWrapperPair()),
primitiveWrapperPairs()
);
}
/**
* return the Java non-reference classes;
* this includes the primitives and void
* (e.g. int, char, boolean, void)
*/
public static Iterator nonReferenceClasses() {
return primitiveClasses(nonReferencePrimitiveWrapperPairs());
}
/**
* return the names of the Java non-reference classes;
* this includes the primitives and void
* (e.g. "int", "char", "boolean", "void")
*/
public static Iterator nonReferenceClassNames() {
return primitiveClassNames(nonReferencePrimitiveWrapperPairs());
}
/**
* return whether the specified class name is
* the name of a Java non-reference classes;
* this includes the primitives and void
* (e.g. "int", "char", "boolean", "void")
*/
public static boolean nonReferenceClassNamesContains(String className) {
return CollectionTools.contains(nonReferenceClassNames(), className);
}
/**
* return the Java non-reference wrapper classes;
* this includes the primitive wrappers and the void "wrapper"
* (e.g. java.lang.Integer, java.lang.Character, java.lang.Void)
*/
public static Iterator nonReferenceWrapperClasses() {
return wrapperClasses(nonReferencePrimitiveWrapperPairs());
}
// ********** member classes **********
/**
* This private class simply associates a primitive with its corresponding
* wrapper class (and vice versa). Once all the necessary instances
* of this class are built, we can use them to determine a primitive's
* wrapper class (or vice versa) with a generic loop of code,
* as opposed to a pair of case statements. And if another primitive
* is ever added to Java, we're ready. :-)
*
* @see MWClass#buildPrimitiveWrapperPairs()
*/
private static class PrimitiveWrapperPair {
private Class primitiveClass;
private Class wrapperClass;
PrimitiveWrapperPair(Class primitiveClass, Class wrapperClass) {
super();
this.primitiveClass = primitiveClass;
this.wrapperClass = wrapperClass;
}
Class getPrimitiveClass() {
return this.primitiveClass;
}
Class getWrapperClass() {
return this.wrapperClass;
}
String primitiveClassName() {
return this.getPrimitiveClass().getName();
}
String wrapperClassName() {
return this.getWrapperClass().getName();
}
}
}