org.eclipse.persistence.jaxb.javamodel.xjc.XJCJavaClassImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* Copyright (c) 2011, 2020 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Rick Barkhouse - 2.1 - Initial implementation
package org.eclipse.persistence.jaxb.javamodel.xjc;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.exceptions.JAXBException;
import org.eclipse.persistence.internal.helper.ClassConstants;
import org.eclipse.persistence.internal.helper.ConversionManager;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.jaxb.javamodel.*;
import com.sun.codemodel.ClassType;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMods;
import com.sun.codemodel.JPrimitiveType;
import com.sun.codemodel.JType;
import com.sun.codemodel.JTypeVar;
/**
* INTERNAL:
*
* Purpose: JavaClass
implementation wrapping XJC's JDefinedClass
.
* Used when bootstrapping a DynamicJAXBContext
from an XML Schema.
*
*
*
* Responsibilities:
*
*
* - Provide Class information from the underlying
JDefinedClass
.
*
*
* @since EclipseLink 2.1
*
* @see org.eclipse.persistence.jaxb.javamodel.JavaClass
*/
public class XJCJavaClassImpl implements JavaClass {
private JDefinedClass xjcClass;
private JCodeModel jCodeModel;
private JavaModel javaModel;
private boolean isArray;
private boolean isPrimitive;
private JavaClass arg;
private DynamicClassLoader dynamicClassLoader;
private static Field JDEFINEDCLASS_ANNOTATIONS = null;
private static Field JDEFINEDCLASS_MODS = null;
private static Field JDEFINEDCLASS_SUPERCLASS = null;
private static Field JTYPEVAR_BOUND = null;
private static final Map jPrimitiveTypes = new HashMap();
static {
JCodeModel tempCodeModel = new JCodeModel();
jPrimitiveTypes.put("java.lang.Boolean", tempCodeModel.BOOLEAN);
jPrimitiveTypes.put("java.lang.Byte", tempCodeModel.BYTE);
jPrimitiveTypes.put("java.lang.Character", tempCodeModel.CHAR);
jPrimitiveTypes.put("java.lang.Double", tempCodeModel.DOUBLE);
jPrimitiveTypes.put("java.lang.Float", tempCodeModel.FLOAT);
jPrimitiveTypes.put("java.lang.Integer", tempCodeModel.INT);
jPrimitiveTypes.put("java.lang.Long", tempCodeModel.LONG);
jPrimitiveTypes.put("java.lang.Short", tempCodeModel.SHORT);
try {
JDEFINEDCLASS_ANNOTATIONS = PrivilegedAccessHelper.getDeclaredField(JDefinedClass.class, "annotations", true);
JDEFINEDCLASS_MODS = PrivilegedAccessHelper.getDeclaredField(JDefinedClass.class, "mods", true);
JDEFINEDCLASS_SUPERCLASS = PrivilegedAccessHelper.getDeclaredField(JDefinedClass.class, "superClass", true);
JTYPEVAR_BOUND = PrivilegedAccessHelper.getDeclaredField(JTypeVar.class, "bound", true);
} catch (Exception e) {
throw JAXBException.errorCreatingDynamicJAXBContext(e);
}
}
/**
* Construct a new instance of XJCJavaClassImpl
.
*
* @param jDefinedClass - the XJC JDefinedClass
to be wrapped.
* @param codeModel - the XJC JCodeModel
this class belongs to.
* @param loader - the ClassLoader
used to bootstrap the DynamicJAXBContext
.
*/
public XJCJavaClassImpl(JDefinedClass jDefinedClass, JCodeModel codeModel, DynamicClassLoader loader) {
this(jDefinedClass, codeModel, loader, false, false);
}
/**
* Construct a new instance of XJCJavaClassImpl
.
*
* @param jDefinedClass - the XJC JDefinedClass
to be wrapped.
* @param codeModel - the XJC JCodeModel
this class belongs to.
* @param loader - the ClassLoader
used to bootstrap the DynamicJAXBContext
.
* @param isArray - indicates that this class is an array type.
* @param isPrimitive - indicates that this class is a primitive type.
*/
public XJCJavaClassImpl(JDefinedClass jDefinedClass, JCodeModel codeModel, DynamicClassLoader loader, boolean isArray, boolean isPrimitive) {
this.xjcClass = jDefinedClass;
this.jCodeModel = codeModel;
this.dynamicClassLoader = loader;
this.isArray = isArray;
this.isPrimitive = isPrimitive;
}
// ========================================================================
public void setActualTypeArgument(JavaClass javaClass){
arg = javaClass;
}
/**
* Return the "actual" type from a parameterized type. For example, if this
* JavaClass
represents List<Employee
, this method will return the
* Employee
JavaClass
.
*
* @return a Collection
containing the actual type's JavaClass
.
*/
@Override
public Collection getActualTypeArguments() {
JTypeVar[] typeParams = xjcClass.typeParams();
if (null == typeParams || 0 == typeParams.length ) {
if(arg != null){
java.util.List theList = new ArrayList(1);
theList.add(arg);
return theList;
}else{
return new ArrayList(0);
}
}
try {
ArrayList typeArguments = new ArrayList(1);
JTypeVar var = typeParams[typeParams.length - 1];
JClass xjcBoundClass = (JClass) PrivilegedAccessHelper.getValueFromField(JTYPEVAR_BOUND, var);
JType basis = null;
try {
// Check to see if this type has a 'basis' field.
// This would indicate it is a "parameterized type" (e.g. List).
// Cannot cache this field because JNarrowedClass is a protected class.
Field basisField = PrivilegedAccessHelper.getDeclaredField(xjcBoundClass.getClass(), "basis", true);
basis = (JClass) PrivilegedAccessHelper.getValueFromField(basisField, xjcBoundClass);
} catch (Exception e) {
// "basis" field not found
}
JavaClass boundClass;
if (basis != null) {
boundClass = this.javaModel.getClass(basis.fullName());
} else if (javaModel != null) {
boundClass = this.javaModel.getClass(xjcBoundClass.fullName());
} else {
JDefinedClass c = jCodeModel._getClass(xjcBoundClass.fullName());
boundClass = new XJCJavaClassImpl(c, jCodeModel, dynamicClassLoader);
}
typeArguments.add(boundClass);
return typeArguments;
} catch (Exception e) {
return new ArrayList(0);
}
}
/**
* If this JavaClass
is an array type, return the type of the
* array components.
*
* @return JavaClass
of this array's component type, or null
if
* this is not an array type.
*/
@Override
public JavaClass getComponentType() {
if (!isArray()) {
return null;
}
return javaModel.getClass(this.xjcClass.fullName());
}
/**
* Return the JavaConstructor
for this JavaClass
that has the
* provided parameter types.
*
* @param parameterTypes the parameter list used to identify the constructor.
*
* @return the JavaConstructor
with the signature matching parameterTypes.
*/
@Override
public JavaConstructor getConstructor(JavaClass[] parameterTypes) {
JType[] xjcParameterTypes = new JType[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
JavaClass pType = parameterTypes[i];
String className = pType.getQualifiedName();
JType xjcType = null;
if (pType.isPrimitive()) {
xjcType = jPrimitiveTypes.get(className);
} else {
xjcType = jCodeModel._getClass(className);
}
xjcParameterTypes[i] = xjcType;
}
JMethod constructor = xjcClass.getConstructor(xjcParameterTypes);
return new XJCJavaConstructorImpl(constructor, jCodeModel, dynamicClassLoader, this);
}
/**
* Return all of the JavaConstructors
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaConstructors
.
*/
@Override
@SuppressWarnings("unchecked")
public Collection getConstructors() {
ArrayList constructors = new ArrayList();
Iterator it = xjcClass.constructors();
while (it.hasNext()) {
constructors.add(new XJCJavaConstructorImpl(it.next(), jCodeModel, dynamicClassLoader, this));
}
return constructors;
}
/**
* Return this JavaClass'
inner classes.
*
* @return A Collection<JavaClass>
containing this JavaClass'
inner classes.
*/
@Override
public Collection getDeclaredClasses() {
ArrayList declaredClasses = new ArrayList();
Iterator it = xjcClass.classes();
while (it.hasNext()) {
XJCJavaClassImpl dc;
if (javaModel != null) {
dc = (XJCJavaClassImpl) this.javaModel.getClass(it.next().fullName());
} else {
dc = new XJCJavaClassImpl(it.next(), jCodeModel, dynamicClassLoader);
}
declaredClasses.add(dc);
}
return declaredClasses;
}
/**
* Return the declared JavaConstructor
for this JavaClass
that has the
* provided parameter types.
*
* @param parameterTypes the parameter list used to identify the constructor.
*
* @return the JavaConstructor
with the signature matching parameterTypes
.
*/
@Override
public JavaConstructor getDeclaredConstructor(JavaClass[] parameterTypes) {
return getConstructor(parameterTypes);
}
/**
* Return all of the declared JavaConstructors
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaConstructors
.
*/
@Override
public Collection getDeclaredConstructors() {
return getConstructors();
}
/**
* Return the declared JavaField
for this JavaClass
, identified
* by fieldName
.
*
* @param fieldName the name of the JavaField
to return.
*
* @return the JavaField
named fieldName
from this JavaClass
.
*/
@Override
public JavaField getDeclaredField(String fieldName) {
JFieldVar xjcField = xjcClass.fields().get(fieldName);
return new XJCJavaFieldImpl(xjcField, jCodeModel, dynamicClassLoader, this);
}
/**
* Return all of the declared JavaFields
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaFields
.
*/
@Override
public Collection getDeclaredFields() {
Collection xjcFields = xjcClass.fields().values();
ArrayList fields = new ArrayList(xjcFields.size());
for (JFieldVar jField : xjcFields) {
fields.add(new XJCJavaFieldImpl(jField, jCodeModel, dynamicClassLoader, this));
}
return fields;
}
/**
* Return the declared JavaMethod
for this JavaClass
,
* identified by name
, with the signature matching args
.
*
* @param name the name of the JavaMethod
to return.
* @param args the parameter list used to identify the method.
*
* @return the matching JavaMethod
from this JavaClass
.
*/
@Override
public JavaMethod getDeclaredMethod(String name, JavaClass[] args) {
return getMethod(name, args);
}
/**
* Return all of the declared JavaMethods
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaMethods
.
*/
@Override
public Collection getDeclaredMethods() {
return getMethods();
}
/**
* Return the JavaMethod
for this JavaClass
, identified
* by name
, with the signature matching args
.
*
* @param name the name of the JavaMethod
to return.
* @param args the parameter list used to identify the method.
*
* @return the matching JavaMethod
from this JavaClass
.
*/
@Override
public JavaMethod getMethod(String name, JavaClass[] args) {
Collection xjcMethods = xjcClass.methods();
for (JMethod xjcMethod : xjcMethods) {
JType[] params = xjcMethod.listParamTypes();
boolean argsAreEqual = argsAreEqual(args, params);
if (xjcMethod.name().equals(name) && argsAreEqual) {
return new XJCJavaMethodImpl(xjcMethod, jCodeModel, dynamicClassLoader, this);
}
}
return null;
}
private boolean argsAreEqual(JavaClass[] elinkArgs, JType[] xjcArgs) {
if (elinkArgs == null && xjcArgs == null) {
return true;
}
if (elinkArgs != null && xjcArgs == null) {
return false;
}
if (elinkArgs == null && xjcArgs != null) {
return false;
}
if (elinkArgs.length != xjcArgs.length) {
return false;
}
for (int i = 0; i < elinkArgs.length; i++) {
JavaClass elinkClass = elinkArgs[i];
JType xjcClass = xjcArgs[i];
if (!elinkClass.getQualifiedName().equals(xjcClass.fullName())) {
return false;
}
}
return true;
}
/**
* Return all of the JavaMethods
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaMethods
.
*/
@Override
public Collection getMethods() {
Collection xjcMethods = xjcClass.methods();
ArrayList elinkMethods = new ArrayList(xjcMethods.size());
for (JMethod xjcMethod : xjcMethods) {
elinkMethods.add(new XJCJavaMethodImpl(xjcMethod, jCodeModel, dynamicClassLoader, this));
}
return elinkMethods;
}
/**
* Returns the Java language modifiers for this JavaClass
, encoded in an integer.
*
* @return the int
representing the modifiers for this class.
*
* @see java.lang.reflect.Modifier
*/
@Override
public int getModifiers() {
JMods xjcMods = null;
try {
xjcMods = (JMods) PrivilegedAccessHelper.getValueFromField(JDEFINEDCLASS_MODS, xjcClass);
} catch (Exception e) {
return 0;
}
return xjcMods.getValue();
}
/**
* Returns the name of this JavaClass
.
*
* @return the String
name of this JavaClass
.
*/
@Override
public String getName() {
return getQualifiedName();
}
/**
* Returns the JavaPackage
that this JavaClass
belongs to.
*
* @return the JavaPackage
of this JavaClass
.
*/
@Override
public JavaPackage getPackage() {
return new XJCJavaPackageImpl(xjcClass.getPackage(), dynamicClassLoader);
}
/**
* Returns the package name of this JavaClass
.
*
* @return the String
name of this JavaClass'
JavaPackage
.
*/
@Override
public String getPackageName() {
return xjcClass._package().name();
}
/**
* Returns the fully-qualified name of this JavaClass
.
*
* @return the String
name of this JavaClass
.
*/
@Override
public String getQualifiedName() {
if(isArray) {
if(this.isPrimitive) {
return getPrimitiveArrayNameFor(xjcClass.fullName());
}
return "[L" + xjcClass.fullName();
}
return xjcClass.fullName();
}
private String getPrimitiveArrayNameFor(String fullName) {
Class> componentClass = ConversionManager.getPrimitiveClass(fullName);
if(componentClass != null) {
if(componentClass == ClassConstants.PBYTE) {
return ClassConstants.APBYTE.getName();
}
if(componentClass == ClassConstants.PCHAR) {
return ClassConstants.APCHAR.getName();
}
if(componentClass == ClassConstants.PBOOLEAN) {
return boolean[].class.getName();
}
if(componentClass == ClassConstants.PDOUBLE) {
return double[].class.getName();
}
if(componentClass == ClassConstants.PFLOAT) {
return float[].class.getName();
}
if(componentClass == ClassConstants.PINT) {
return int[].class.getName();
}
if(componentClass == ClassConstants.PLONG) {
return long[].class.getName();
}
if(componentClass == ClassConstants.PSHORT) {
return short[].class.getName();
}
}
return fullName;
}
/**
* Returns the raw name of this JavaClass
. Array types will
* have "[]" appended to the name.
*
* @return the String
raw name of this JavaClass
.
*/
@Override
public String getRawName() {
if(isArray) {
return xjcClass.fullName() + "[]";
}
return xjcClass.fullName();
}
/**
* Returns the super class of this JavaClass
.
*
* @return JavaClass
representing the super class of this JavaClass
.
*/
@Override
public JavaClass getSuperclass() {
try {
JClass superClass = (JClass) PrivilegedAccessHelper.getValueFromField(JDEFINEDCLASS_SUPERCLASS, xjcClass);
if (superClass == null) // if null -> no need to continue
return null;
if (superClass instanceof JDefinedClass) {
if (javaModel != null) {
return this.javaModel.getClass(superClass.fullName());
}
return new XJCJavaClassImpl((JDefinedClass) superClass, jCodeModel, dynamicClassLoader);
} else {
if (javaModel != null) {
return this.javaModel.getClass(superClass.fullName());
}
return new XJCJavaClassImpl((JDefinedClass) superClass, jCodeModel, dynamicClassLoader);
}
} catch (Exception e) {
return null;
}
}
@Override
public Type[] getGenericInterfaces() {
return new Type[0];
}
@Override
public Type getGenericSuperclass() {
return null;
}
/**
* Indicates if this JavaClass
has actual type arguments, i.e. is a
* parameterized type (for example, List<Employee
).
*
* @return true
if this JavaClass
is parameterized, otherwise false
.
*/
@Override
public boolean hasActualTypeArguments() {
return xjcClass.typeParams().length > 0;
}
/**
* Indicates if this JavaClass
is abstract
.
*
* @return true
if this JavaClass
is abstract
, otherwise false
.
*/
@Override
public boolean isAbstract() {
return xjcClass.isAbstract();
}
/**
* Indicates if this JavaClass
is an Annotation
.
*
* @return true
if this JavaClass
is an Annotation
, otherwise false
.
*/
@Override
public boolean isAnnotation() {
return xjcClass.isAnnotationTypeDeclaration();
}
/**
* Indicates if this JavaClass
is an Array type.
*
* @return true
if this JavaClass
is an Array type, otherwise false
.
*/
@Override
public boolean isArray() {
if (this.isArray) {
return true;
}
return this.xjcClass.isArray();
}
/**
* Indicates if this JavaClass
is either the same as, or is a superclass of,
* the javaClass
argument.
*
* @param javaClass the Class
to test.
*
* @return true
if this JavaClass
is assignable from
* javaClass
, otherwise false
.
*
* @see java.lang.Class#isAssignableFrom(Class)
*/
@Override
public boolean isAssignableFrom(JavaClass javaClass) {
if (javaClass == null) {
return false;
}
XJCJavaClassImpl javaClassImpl = (XJCJavaClassImpl) javaClass;
JClass someClass = javaClassImpl.xjcClass;
return xjcClass.isAssignableFrom(someClass);
}
/**
* Indicates if this JavaClass
is an enum
.
*
* @return true
if this JavaClass
is an enum
, otherwise false
.
*/
@Override
public boolean isEnum() {
return xjcClass.getClassType().equals(ClassType.ENUM);
}
/**
* Indicates if this JavaClass
is final
.
*
* @return true
if this JavaClass
is final
, otherwise false
.
*/
@Override
public boolean isFinal() {
return Modifier.isFinal(getModifiers());
}
/**
* Indicates if this JavaClass
is an interface
.
*
* @return true
if this JavaClass
is an interface
, otherwise false
.
*/
@Override
public boolean isInterface() {
return xjcClass.isInterface();
}
/**
* Indicates if this JavaClass
is an inner Class
.
*
* @return true
if this JavaClass
is an inner Class
, otherwise false
.
*/
@Override
public boolean isMemberClass() {
return this.xjcClass.outer() != null;
}
/**
* Indicates if this JavaClass
represents a primitive type.
*
* @return true
if this JavaClass
represents a primitive type, otherwise false
.
*/
@Override
public boolean isPrimitive() {
return false;
}
/**
* Indicates if this JavaClass
is private
.
*
* @return true
if this JavaClass
is private
, otherwise false
.
*/
@Override
public boolean isPrivate() {
return Modifier.isPrivate(getModifiers());
}
/**
* Indicates if this JavaClass
is protected
.
*
* @return true
if this JavaClass
is protected
, otherwise false
.
*/
@Override
public boolean isProtected() {
return Modifier.isProtected(getModifiers());
}
/**
* Indicates if this JavaClass
is public
.
*
* @return true
if this JavaClass
is public
, otherwise false
.
*/
@Override
public boolean isPublic() {
return Modifier.isPublic(getModifiers());
}
/**
* Indicates if this JavaClass
is static
.
*
* @return true
if this JavaClass
is static
, otherwise false
.
*/
@Override
public boolean isStatic() {
return Modifier.isStatic(getModifiers());
}
/**
* Not supported.
*/
@Override
public boolean isSynthetic() {
throw new UnsupportedOperationException("isSynthetic");
}
@Override
public JavaClassInstanceOf instanceOf() {
return JavaClassInstanceOf.XJC_JAVA_CLASS_IMPL;
}
/**
* If this JavaClass
is annotated with an Annotation
matching aClass
,
* return its JavaAnnotation
representation.
*
* @param aClass a JavaClass
representing the Annotation
to look for.
*
* @return the JavaAnnotation
represented by aClass
, if one exists, otherwise return null
.
*/
@Override
@SuppressWarnings("unchecked")
public JavaAnnotation getAnnotation(JavaClass aClass) {
if (aClass != null) {
Collection annotations = null;
try {
annotations = (Collection) PrivilegedAccessHelper.getValueFromField(JDEFINEDCLASS_ANNOTATIONS, xjcClass);
} catch (Exception e) {
}
if (annotations == null) {
return null;
}
for (JAnnotationUse annotationUse : annotations) {
XJCJavaAnnotationImpl xjcAnnotation = new XJCJavaAnnotationImpl(annotationUse, dynamicClassLoader);
String myAnnotationClass = xjcAnnotation.getJavaAnnotationClass().getCanonicalName();
String annotationClass = aClass.getQualifiedName();
if (myAnnotationClass.equals(annotationClass)) {
return xjcAnnotation;
}
}
// Didn't find annotation so return null
return null;
}
// aClass was null so return null
return null;
}
/**
* Return all of the Annotations
for this JavaClass
.
*
* @return A Collection
containing this JavaClass'
JavaAnnotations
.
*/
@Override
@SuppressWarnings("unchecked")
public Collection getAnnotations() {
ArrayList annotationsList = new ArrayList();
Collection annotations = null;
try {
annotations = (Collection) PrivilegedAccessHelper.getValueFromField(JDEFINEDCLASS_ANNOTATIONS, xjcClass);
} catch (Exception e) {
}
if (annotations == null) {
return annotationsList;
}
for (JAnnotationUse annotationUse : annotations) {
XJCJavaAnnotationImpl xjcAnnotation = new XJCJavaAnnotationImpl(annotationUse, dynamicClassLoader);
annotationsList.add(xjcAnnotation);
}
return annotationsList;
}
/**
* Not supported.
*/
@Override
public JavaAnnotation getDeclaredAnnotation(JavaClass arg0) {
return getAnnotation(arg0);
}
/**
* Not supported.
*/
@Override
public Collection getDeclaredAnnotations() {
return getAnnotations();
}
/**
* Get this JavaClass'
JavaModel
.
*
* @return The JavaModel
associated with this JavaClass
.
*/
public JavaModel getJavaModel() {
return javaModel;
}
/**
* Set this JavaClass'
JavaModel
.
*
* @param javaModel The JavaModel
to set.
*/
public void setJavaModel(JavaModel javaModel) {
this.javaModel = javaModel;
}
}