/******************************************************************************* | |
* Copyright (c) 1998, 2013 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.jaxb.javamodel.reflection; | |
import org.eclipse.persistence.exceptions.JAXBException; | |
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; | |
import org.eclipse.persistence.jaxb.javamodel.JavaAnnotation; | |
import org.eclipse.persistence.jaxb.javamodel.JavaClass; | |
import org.eclipse.persistence.jaxb.javamodel.JavaConstructor; | |
import org.eclipse.persistence.jaxb.javamodel.JavaField; | |
import org.eclipse.persistence.jaxb.javamodel.JavaMethod; | |
import org.eclipse.persistence.jaxb.javamodel.JavaPackage; | |
import java.lang.annotation.Annotation; | |
import java.lang.reflect.AnnotatedElement; | |
import java.lang.reflect.Constructor; | |
import java.lang.reflect.Field; | |
import java.lang.reflect.GenericArrayType; | |
import java.lang.reflect.Method; | |
import java.lang.reflect.Modifier; | |
import java.lang.reflect.ParameterizedType; | |
import java.lang.reflect.Type; | |
import java.lang.reflect.TypeVariable; | |
import java.lang.reflect.WildcardType; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
/** | |
* INTERNAL: | |
* <p><b>Purpose:</b>A wrapper class for a JDK Class. This implementation | |
* of the EclipseLink JAXB 2.X Java model simply makes reflective calls on the | |
* underlying JDK object. | |
* | |
* <p><b>Responsibilities:</b> | |
* <ul> | |
* <li>Provide access to the underlying JDK Class' name, package, | |
* method/field names and parameters, annotations, etc.</li> | |
* </ul> | |
* | |
* @since Oracle TopLink 11.1.1.0.0 | |
* @see org.eclipse.persistence.jaxb.javamodel.JavaClass | |
* @see java.lang.Class | |
*/ | |
public class JavaClassImpl implements JavaClass { | |
protected ParameterizedType jType; | |
protected Class jClass; | |
protected JavaModelImpl javaModelImpl; | |
protected boolean isMetadataComplete; | |
protected JavaClass superClassOverride; | |
protected static String XML_REGISTRY_CLASS_NAME = "javax.xml.bind.annotation.XmlRegistry"; | |
public JavaClassImpl(Class javaClass, JavaModelImpl javaModelImpl) { | |
this.jClass = javaClass; | |
this.javaModelImpl = javaModelImpl; | |
isMetadataComplete = false; | |
} | |
public JavaClassImpl(ParameterizedType javaType, Class javaClass, JavaModelImpl javaModelImpl) { | |
this.jType = javaType; | |
this.jClass = javaClass; | |
this.javaModelImpl = javaModelImpl; | |
isMetadataComplete = false; | |
} | |
public void setJavaModelImpl(JavaModelImpl javaModel) { | |
this.javaModelImpl = javaModel; | |
} | |
public Collection getActualTypeArguments() { | |
ArrayList<JavaClass> argCollection = new ArrayList<JavaClass>(); | |
if (jType instanceof ParameterizedType) { | |
ParameterizedType pType = (ParameterizedType) jType; | |
Type[] params = pType.getActualTypeArguments(); | |
for (Type type : params) { | |
if (type instanceof ParameterizedType) { | |
ParameterizedType pt = (ParameterizedType) type; | |
argCollection.add(new JavaClassImpl(pt, (Class) pt.getRawType(), javaModelImpl)); | |
} else if(type instanceof WildcardType){ | |
Type[] upperTypes = ((WildcardType)type).getUpperBounds(); | |
if(upperTypes.length >0){ | |
Type upperType = upperTypes[0]; | |
if(upperType instanceof Class){ | |
argCollection.add(javaModelImpl.getClass((Class) upperType)); | |
} | |
} | |
} else if (type instanceof Class) { | |
argCollection.add(javaModelImpl.getClass((Class) type)); | |
} else if(type instanceof GenericArrayType) { | |
Class genericTypeClass = (Class)((GenericArrayType)type).getGenericComponentType(); | |
genericTypeClass = java.lang.reflect.Array.newInstance(genericTypeClass, 0).getClass(); | |
argCollection.add(javaModelImpl.getClass(genericTypeClass)); | |
} else if(type instanceof TypeVariable) { | |
Type[] boundTypes = ((TypeVariable) type).getBounds(); | |
if(boundTypes.length > 0) { | |
Type boundType = boundTypes[0]; | |
if(boundType instanceof Class) { | |
argCollection.add(javaModelImpl.getClass((Class) boundType)); | |
} | |
} | |
} | |
} | |
} | |
return argCollection; | |
} | |
public String toString() { | |
return getName(); | |
} | |
/** | |
* Assumes JavaType is a JavaClassImpl instance | |
*/ | |
public JavaAnnotation getAnnotation(JavaClass arg0) { | |
// the only annotation we will return if isMetadataComplete == true is XmlRegistry | |
if (arg0 != null && (!isMetadataComplete || arg0.getQualifiedName().equals(XML_REGISTRY_CLASS_NAME))) { | |
Class annotationClass = ((JavaClassImpl) arg0).getJavaClass(); | |
if (javaModelImpl.getAnnotationHelper().isAnnotationPresent(getAnnotatedElement(), annotationClass)) { | |
return new JavaAnnotationImpl(this.javaModelImpl.getAnnotationHelper().getAnnotation(getAnnotatedElement(), annotationClass)); | |
} | |
} | |
return null; | |
} | |
public Collection getAnnotations() { | |
ArrayList<JavaAnnotation> annotationCollection = new ArrayList<JavaAnnotation>(); | |
if (!isMetadataComplete) { | |
Annotation[] annotations = javaModelImpl.getAnnotationHelper().getAnnotations(getAnnotatedElement()); | |
for (Annotation annotation : annotations) { | |
annotationCollection.add(new JavaAnnotationImpl(annotation)); | |
} | |
} | |
return annotationCollection; | |
} | |
public Collection getDeclaredClasses() { | |
ArrayList<JavaClass> classCollection = new ArrayList<JavaClass>(); | |
Class[] classes = jClass.getDeclaredClasses(); | |
for (Class javaClass : classes) { | |
classCollection.add(javaModelImpl.getClass(javaClass)); | |
} | |
return classCollection; | |
} | |
public JavaField getDeclaredField(String arg0) { | |
try { | |
return getJavaField(jClass.getDeclaredField(arg0)); | |
} catch (NoSuchFieldException nsfe) { | |
return null; | |
} | |
} | |
public Collection getDeclaredFields() { | |
ArrayList<JavaField> fieldCollection = new ArrayList<JavaField>(); | |
Field[] fields = PrivilegedAccessHelper.getDeclaredFields(jClass); | |
for (Field field : fields) { | |
field.setAccessible(true); | |
fieldCollection.add(getJavaField(field)); | |
} | |
return fieldCollection; | |
} | |
/** | |
* Assumes JavaType[] contains JavaClassImpl instances | |
*/ | |
public JavaMethod getDeclaredMethod(String arg0, JavaClass[] arg1) { | |
if (arg1 == null) { | |
arg1 = new JavaClass[0]; | |
} | |
Class[] params = new Class[arg1.length]; | |
for (int i=0; i<arg1.length; i++) { | |
JavaClass jType = arg1[i]; | |
if (jType != null) { | |
params[i] = ((JavaClassImpl) jType).getJavaClass(); | |
} | |
} | |
try { | |
return getJavaMethod(jClass.getDeclaredMethod(arg0, params)); | |
} catch (NoSuchMethodException nsme) { | |
return null; | |
} | |
} | |
public Collection getDeclaredMethods() { | |
ArrayList<JavaMethod> methodCollection = new ArrayList<JavaMethod>(); | |
Method[] methods = jClass.getDeclaredMethods(); | |
for (Method method : methods) { | |
methodCollection.add(getJavaMethod(method)); | |
} | |
return methodCollection; | |
} | |
public JavaConstructor getConstructor(JavaClass[] paramTypes) { | |
if (paramTypes == null) { | |
paramTypes = new JavaClass[0]; | |
} | |
Class[] params = new Class[paramTypes.length]; | |
for (int i=0; i<paramTypes.length; i++) { | |
JavaClass jType = paramTypes[i]; | |
if (jType != null) { | |
params[i] = ((JavaClassImpl) jType).getJavaClass(); | |
} | |
} | |
try { | |
Constructor constructor = PrivilegedAccessHelper.getConstructorFor(jClass, params, true); | |
return new JavaConstructorImpl(constructor, javaModelImpl); | |
} catch (NoSuchMethodException nsme) { | |
return null; | |
} | |
} | |
public JavaConstructor getDeclaredConstructor(JavaClass[] paramTypes) { | |
if (paramTypes == null) { | |
paramTypes = new JavaClass[0]; | |
} | |
Class[] params = new Class[paramTypes.length]; | |
for (int i=0; i<paramTypes.length; i++) { | |
JavaClass jType = paramTypes[i]; | |
if (jType != null) { | |
params[i] = ((JavaClassImpl) jType).getJavaClass(); | |
} | |
} | |
try { | |
return new JavaConstructorImpl(PrivilegedAccessHelper.getDeclaredConstructorFor(this.jClass, params, true), javaModelImpl); | |
} catch (NoSuchMethodException nsme) { | |
return null; | |
} | |
} | |
public Collection getConstructors() { | |
Constructor[] constructors = this.jClass.getConstructors(); | |
ArrayList<JavaConstructor> constructorCollection = new ArrayList(constructors.length); | |
for(Constructor next:constructors) { | |
constructorCollection.add(new JavaConstructorImpl(next, javaModelImpl)); | |
} | |
return constructorCollection; | |
} | |
public Collection getDeclaredConstructors() { | |
Constructor[] constructors = this.jClass.getDeclaredConstructors(); | |
ArrayList<JavaConstructor> constructorCollection = new ArrayList(constructors.length); | |
for(Constructor next:constructors) { | |
constructorCollection.add(new JavaConstructorImpl(next, javaModelImpl)); | |
} | |
return constructorCollection; | |
} | |
public JavaField getField(String arg0) { | |
try { | |
Field field = PrivilegedAccessHelper.getField(jClass, arg0, true); | |
return getJavaField(field); | |
} catch (NoSuchFieldException nsfe) { | |
return null; | |
} | |
} | |
public Collection getFields() { | |
ArrayList<JavaField> fieldCollection = new ArrayList<JavaField>(); | |
Field[] fields = PrivilegedAccessHelper.getFields(jClass); | |
for (Field field : fields) { | |
fieldCollection.add(getJavaField(field)); | |
} | |
return fieldCollection; | |
} | |
public Class getJavaClass() { | |
return jClass; | |
} | |
/** | |
* Assumes JavaType[] contains JavaClassImpl instances | |
*/ | |
public JavaMethod getMethod(String arg0, JavaClass[] arg1) { | |
if (arg1 == null) { | |
arg1 = new JavaClass[0]; | |
} | |
Class[] params = new Class[arg1.length]; | |
for (int i=0; i<arg1.length; i++) { | |
JavaClass jType = arg1[i]; | |
if (jType != null) { | |
params[i] = ((JavaClassImpl) jType).getJavaClass(); | |
} | |
} | |
try { | |
Method method = PrivilegedAccessHelper.getMethod(jClass, arg0, params, true); | |
return getJavaMethod(method); | |
} catch (NoSuchMethodException nsme) { | |
return null; | |
} | |
} | |
public Collection getMethods() { | |
ArrayList<JavaMethod> methodCollection = new ArrayList<JavaMethod>(); | |
Method[] methods = PrivilegedAccessHelper.getMethods(jClass); | |
for (Method method : methods) { | |
methodCollection.add(getJavaMethod(method)); | |
} | |
return methodCollection; | |
} | |
public String getName() { | |
return jClass.getName(); | |
} | |
public JavaPackage getPackage() { | |
return new JavaPackageImpl(jClass.getPackage(), javaModelImpl, isMetadataComplete); | |
} | |
public String getPackageName() { | |
if(jClass.getPackage() != null){ | |
return jClass.getPackage().getName(); | |
}else{ | |
Class nonInnerClass = jClass; | |
Class enclosingClass = jClass.getEnclosingClass(); | |
while(enclosingClass != null){ | |
nonInnerClass = enclosingClass; | |
enclosingClass = nonInnerClass.getEnclosingClass(); | |
} | |
String className = nonInnerClass.getCanonicalName(); | |
if(className !=null){ | |
int index = className.lastIndexOf("."); | |
if(index > -1){ | |
return className.substring(0, index); | |
} | |
} | |
} | |
return null; | |
} | |
public String getQualifiedName() { | |
return jClass.getName(); | |
} | |
public String getRawName() { | |
return jClass.getCanonicalName(); | |
} | |
public JavaClass getSuperclass() { | |
if(this.superClassOverride != null) { | |
return this.superClassOverride; | |
} | |
if(jClass.isInterface()) { | |
Class[] superInterfaces = jClass.getInterfaces(); | |
if(superInterfaces != null) { | |
if(superInterfaces.length == 1) { | |
return javaModelImpl.getClass(superInterfaces[0]); | |
} else { | |
Class parent = null; | |
for(Class next:superInterfaces) { | |
if(!(next.getName().startsWith("java.") || next.getName().startsWith("javax."))) { | |
if(parent == null) { | |
parent = next; | |
} else { | |
throw JAXBException.invalidInterface(jClass.getName()); | |
} | |
} | |
} | |
return javaModelImpl.getClass(parent); | |
} | |
} | |
} | |
return javaModelImpl.getClass(jClass.getSuperclass()); | |
} | |
@Override | |
public Type[] getGenericInterfaces() { | |
return jClass.getGenericInterfaces(); | |
} | |
public Type getGenericSuperclass() { | |
return jClass.getGenericSuperclass(); | |
} | |
public boolean hasActualTypeArguments() { | |
return getActualTypeArguments().size() > 0; | |
} | |
public JavaField getJavaField(Field field) { | |
return new JavaFieldImpl(field, javaModelImpl, isMetadataComplete); | |
} | |
public JavaMethod getJavaMethod(Method method) { | |
return new JavaMethodImpl(method, javaModelImpl, isMetadataComplete); | |
} | |
public JavaClass getOwningClass() { | |
return javaModelImpl.getClass(jClass.getEnclosingClass()); | |
} | |
public boolean isAnnotation() { | |
return jClass.isAnnotation(); | |
} | |
public boolean isArray() { | |
return jClass.isArray(); | |
} | |
public AnnotatedElement getAnnotatedElement() { | |
return jClass; | |
} | |
public boolean isAssignableFrom(JavaClass arg0) { | |
if (!(arg0 instanceof JavaClassImpl)) { | |
return false; | |
} | |
if(hasCustomSuperClass(arg0)) { | |
return this.customIsAssignableFrom(arg0); | |
} | |
return jClass.isAssignableFrom(((JavaClassImpl) arg0).getJavaClass()); | |
} | |
private boolean customIsAssignableFrom(JavaClass arg0) { | |
JavaClassImpl jClass = (JavaClassImpl)arg0; | |
Class cls = jClass.getJavaClass(); | |
if(cls == this.jClass) { | |
return true; | |
} | |
Class[] interfaces = cls.getInterfaces(); | |
for(Class nextInterface:interfaces) { | |
if(nextInterface == this.jClass) { | |
return true; | |
} | |
if(customIsAssignableFrom(javaModelImpl.getClass(nextInterface))) { | |
return true; | |
} | |
} | |
if(!(jClass.isInterface())) { | |
JavaClassImpl superJavaClass = (JavaClassImpl)jClass.getSuperclass(); | |
if(superJavaClass.getName().equals("java.lang.Object")) { | |
return this.jClass == superJavaClass.getJavaClass(); | |
} | |
return customIsAssignableFrom(superJavaClass); | |
} | |
return false; | |
} | |
private boolean hasCustomSuperClass(JavaClass arg0) { | |
if(arg0 == null) { | |
return false; | |
} | |
if(!this.javaModelImpl.hasXmlBindings()) { | |
return false; | |
} | |
if(!(arg0.getClass() == this.getClass())) { | |
return false; | |
} | |
if(arg0.getName().equals("java.lang.Object")) { | |
return false; | |
} | |
JavaClassImpl jClass = (JavaClassImpl)arg0; | |
if(jClass.getSuperClassOverride() != null) { | |
return true; | |
} | |
return hasCustomSuperClass(jClass.getSuperclass()); | |
} | |
public boolean isEnum() { | |
return jClass.isEnum(); | |
} | |
public boolean isInterface() { | |
return jClass.isInterface(); | |
} | |
public boolean isMemberClass() { | |
return jClass.isMemberClass(); | |
} | |
public boolean isPrimitive() { | |
return jClass.isPrimitive(); | |
} | |
public boolean isAbstract() { | |
return Modifier.isAbstract(getModifiers()); | |
} | |
public boolean isPrivate() { | |
return Modifier.isPrivate(getModifiers()); | |
} | |
public boolean isProtected() { | |
return Modifier.isProtected(getModifiers()); | |
} | |
public boolean isPublic() { | |
return Modifier.isPublic(getModifiers()); | |
} | |
public boolean isStatic() { | |
return Modifier.isStatic(getModifiers()); | |
} | |
public int getModifiers() { | |
return jClass.getModifiers(); | |
} | |
public boolean isFinal() { | |
return Modifier.isFinal(getModifiers()); | |
} | |
public boolean isSynthetic() { | |
return jClass.isSynthetic(); | |
} | |
public JavaClass getComponentType() { | |
if(!isArray()) { | |
return null; | |
} | |
return javaModelImpl.getClass(this.jClass.getComponentType()); | |
} | |
public JavaClass getSuperClassOverride() { | |
return superClassOverride; | |
} | |
public void setSuperClassOverride(JavaClass superClassOverride) { | |
this.superClassOverride = superClassOverride; | |
} | |
/** | |
* Set the indicator for XML metadata complete - if true, | |
* annotations will be ignored. | |
* | |
* @param isMetadataComplete | |
*/ | |
void setIsMetadataComplete(Boolean isMetadataComplete) { | |
if(isMetadataComplete != null){ | |
this.isMetadataComplete = isMetadataComplete; | |
} | |
} | |
public JavaAnnotation getDeclaredAnnotation(JavaClass arg0) { | |
// the only annotation we will return if isMetadataComplete == true is XmlRegistry | |
if (arg0 != null && (!isMetadataComplete || arg0.getQualifiedName().equals(XML_REGISTRY_CLASS_NAME))) { | |
Class annotationClass = ((JavaClassImpl) arg0).getJavaClass(); | |
Annotation[] annotations = javaModelImpl.getAnnotationHelper().getDeclaredAnnotations(getAnnotatedElement()); | |
for (Annotation annotation : annotations) { | |
if (annotation.annotationType().equals(annotationClass)) { | |
return new JavaAnnotationImpl(annotation); | |
} | |
} | |
} | |
return null; | |
} | |
public Collection getDeclaredAnnotations() { | |
ArrayList<JavaAnnotation> annotationCollection = new ArrayList<JavaAnnotation>(); | |
if (!isMetadataComplete) { | |
Annotation[] annotations = javaModelImpl.getAnnotationHelper().getDeclaredAnnotations(getAnnotatedElement()); | |
for (Annotation annotation : annotations) { | |
annotationCollection.add(new JavaAnnotationImpl(annotation)); | |
} | |
} | |
return annotationCollection; | |
} | |
} |