blob: 7851896410d9d9dad09a55aed86fb2f54d2b8bd6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 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:
* 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.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
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.JavaField;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JPrimitiveType;
import com.sun.codemodel.JType;
import com.sun.codemodel.JVar;
/**
* INTERNAL:
* <p>
* <b>Purpose:</b> <code>JavaField</code> implementation wrapping XJC's <code>JFieldVar</code>. Used when
* bootstrapping a <code>DynamicJAXBContext</code> from an XML Schema.
* </p>
*
* <p>
* <b>Responsibilities:</b>
* <ul>
* <li>Provide <code>Field</code> information from the underlying <code>JFieldVar</code>.</li>
* </ul>
* </p>
*
* @since EclipseLink 2.1
*
* @see org.eclipse.persistence.jaxb.javamodel.JavaField
*/
public class XJCJavaFieldImpl implements JavaField {
private JFieldVar xjcField;
private JCodeModel jCodeModel;
private DynamicClassLoader dynamicClassLoader;
private JavaClass owningClass;
private static Field JVAR_ANNOTATIONS = null;
private static Field JARRAYCLASS_COMPONENTTYPE = null;
static {
try {
JVAR_ANNOTATIONS = PrivilegedAccessHelper.getDeclaredField(JVar.class, "annotations", true);
Class<?> c = Class.forName("com.sun.codemodel.JArrayClass");
JARRAYCLASS_COMPONENTTYPE = PrivilegedAccessHelper.getDeclaredField(c, "componentType", true);
} catch (Exception e) {
throw JAXBException.errorCreatingDynamicJAXBContext(e);
}
}
/**
* Construct a new instance of <code>XJCJavaFieldImpl</code>.
*
* @param javaField - the XJC <code>JFieldVar</code> to be wrapped.
* @param codeModel - the XJC <code>JCodeModel</code> this field belongs to.
* @param loader - the <code>ClassLoader</code> used to bootstrap the <code>DynamicJAXBContext</code>.
* @param owner - the <code>JavaClass</code> this field belongs to.
*/
public XJCJavaFieldImpl(JFieldVar javaField, JCodeModel codeModel, DynamicClassLoader loader, JavaClass owner) {
this.xjcField = javaField;
this.jCodeModel = codeModel;
this.dynamicClassLoader = loader;
this.owningClass = owner;
}
/**
* If this <code>JavaField</code> is annotated with an <code>Annotation</code> matching <code>aClass</code>,
* return its <code>JavaAnnotation</code> representation.
*
* @param aClass a <code>JavaClass</code> representing the <code>Annotation</code> to look for.
*
* @return the <code>JavaAnnotation</code> represented by <code>aClass</code>, if one exists, otherwise return <code>null</code>.
*/
@SuppressWarnings("unchecked")
public JavaAnnotation getAnnotation(JavaClass aClass) {
if (aClass != null) {
Collection<JAnnotationUse> annotations = null;
try {
annotations = (Collection<JAnnotationUse>) PrivilegedAccessHelper.getValueFromField(JVAR_ANNOTATIONS, xjcField);
} catch (Exception e) {
}
if (annotations == null) {
return null;
}
for (JAnnotationUse annotationUse : annotations) {
XJCJavaAnnotationImpl xjcAnnotation = new XJCJavaAnnotationImpl(annotationUse, dynamicClassLoader);
if (xjcAnnotation.getJavaAnnotationClass().getCanonicalName().equals(aClass.getQualifiedName())) {
return xjcAnnotation;
}
}
// Didn't find annotation so return null
return null;
}
// aClass was null so return null
return null;
}
/**
* Return all of the <code>Annotations</code> for this <code>JavaField</code>.
*
* @return A <code>Collection</code> containing this <code>JavaField's</code> <code>JavaAnnotations</code>.
*/
@SuppressWarnings("unchecked")
public Collection<JavaAnnotation> getAnnotations() {
ArrayList<JavaAnnotation> annotationsList = new ArrayList<JavaAnnotation>();
Collection<JAnnotationUse> annotations = null;
try {
annotations = (Collection<JAnnotationUse>) PrivilegedAccessHelper.getValueFromField(JVAR_ANNOTATIONS, xjcField);
} catch (Exception e) {
}
if (annotations != null) {
for (JAnnotationUse annotationUse : annotations) {
XJCJavaAnnotationImpl xjcAnnotation = new XJCJavaAnnotationImpl(annotationUse, dynamicClassLoader);
annotationsList.add(xjcAnnotation);
}
}
return annotationsList;
}
/**
* Returns the Java language modifiers for this <code>JavaField</code>, encoded in an integer.
*
* @return the <code>int</code> representing the modifiers for this field.
*
* @see java.lang.reflect.Modifier
*/
public int getModifiers() {
return xjcField.mods().getValue();
}
/**
* Returns the name of this <code>JavaField</code>.
*
* @return the <code>String</code> name of this <code>JavaField</code>.
*/
public String getName() {
return xjcField.name();
}
/**
* Returns the <code>JavaClass</code> representing the type of this <code>JavaField</code>.
*
* @return the type of this <code>JavaField</code> as a <code>JavaClass</code>.
*/
@SuppressWarnings("unchecked")
public JavaClass getResolvedType() {
JType type = xjcField.type();
JType basis = null;
boolean isArray = false;
boolean isPrimitive = false;
try {
// Check to see if this type has a 'basis' field.
// This would indicate it is a "parameterized type" (e.g. List<Employee>).
// Cannot cache this field because JNarrowedClass is a protected class.
Field basisField = PrivilegedAccessHelper.getDeclaredField(type.getClass(), "basis", true);
basis = (JClass) PrivilegedAccessHelper.getValueFromField(basisField, type);
} catch (Exception e) {
// "basis" field not found
}
JClass classToReturn = null;
if (type.isPrimitive()) {
JPrimitiveType pType = (JPrimitiveType) type;
classToReturn = pType.boxify();
} else if (type.getClass().getName().contains("JArrayClass")) {
isArray = true;
classToReturn = (JClass) type;
try {
JType componentType = (JType) PrivilegedAccessHelper.getValueFromField(JARRAYCLASS_COMPONENTTYPE, type);
if (componentType.isPrimitive()) {
isPrimitive = true;
}
} catch (Exception e) {
throw JAXBException.errorCreatingDynamicJAXBContext(e);
}
} else {
try {
classToReturn = jCodeModel._class(basis != null ? basis.fullName() : type.fullName());
} catch (JClassAlreadyExistsException ex) {
classToReturn = jCodeModel._getClass(basis != null ? basis.fullName() : type.fullName());
}
}
if (basis != null) {
try {
// Cannot cache this field because JNarrowedClass is a protected class.
Field argsField = PrivilegedAccessHelper.getDeclaredField(type.getClass(), "args", true);
List<JClass> args = (List<JClass>) PrivilegedAccessHelper.getValueFromField(argsField, type);
for (JClass jClass : args) {
((JDefinedClass) classToReturn).generify("param", jClass);
}
} catch (Exception e) {
throw JAXBException.errorCreatingDynamicJAXBContext(e);
}
}
String className = classToReturn.fullName();
if (isArray) {
className += "[]";
}
if (((XJCJavaClassImpl) getOwningClass()).getJavaModel() != null) {
return ((XJCJavaClassImpl) getOwningClass()).getJavaModel().getClass(className);
}
return new XJCJavaClassImpl((JDefinedClass) classToReturn, jCodeModel, dynamicClassLoader, isArray, isPrimitive);
}
/**
* Indicates if this <code>JavaField</code> is <code>final</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>final</code>, otherwise <code>false</code>.
*/
public boolean isFinal() {
return Modifier.isFinal(getModifiers());
}
/**
* Indicates if this <code>JavaField</code> is <code>abstract</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>abstract</code>, otherwise <code>false</code>.
*/
public boolean isAbstract() {
return Modifier.isAbstract(getModifiers());
}
/**
* Indicates if this <code>JavaField</code> is <code>private</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>private</code>, otherwise <code>false</code>.
*/
public boolean isPrivate() {
return Modifier.isPrivate(getModifiers());
}
/**
* Indicates if this <code>JavaField</code> is <code>protected</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>protected</code>, otherwise <code>false</code>.
*/
public boolean isProtected() {
return Modifier.isProtected(getModifiers());
}
/**
* Indicates if this <code>JavaField</code> is <code>public</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>public</code>, otherwise <code>false</code>.
*/
public boolean isPublic() {
return Modifier.isPublic(getModifiers());
}
/**
* Indicates if this <code>JavaField</code> is <code>static</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is <code>static</code>, otherwise <code>false</code>.
*/
public boolean isStatic() {
return Modifier.isStatic(getModifiers());
}
/**
* Not supported.
*/
public boolean isSynthetic() {
throw new UnsupportedOperationException("isSynthetic");
}
/**
* Indicates if this <code>JavaField</code> is an <code>enum</code> constant - i.e. its owner is an <code>enum</code>.
*
* @return <code>true</code> if this <code>JavaField</code> is an <code>enum</code> constant.
*/
public boolean isEnumConstant() {
return getOwningClass().isEnum();
}
/**
* If this <code>JavaField</code> is annotated with an <code>Annotation</code> matching <code>aClass</code>,
* return its <code>JavaAnnotation</code> representation.
*
* @param aClass a <code>JavaClass</code> representing the <code>Annotation</code> to look for.
*
* @return the <code>JavaAnnotation</code> represented by <code>aClass</code>, if one exists, otherwise return <code>null</code>.
*/
public JavaAnnotation getDeclaredAnnotation(JavaClass aClass) {
return getAnnotation(aClass);
}
/**
* Return all of the <code>Annotations</code> for this <code>JavaField</code>.
*
* @return A <code>Collection</code> containing this <code>JavaField's</code> <code>JavaAnnotations</code>.
*/
public Collection<JavaAnnotation> getDeclaredAnnotations() {
return getAnnotations();
}
/**
* Set the <code>JavaClass</code> which contains this field.
*
* @param owningClass the <code>JavaClass</code> representing the owner of this <code>JavaField</code>.
*/
public void setOwningClass(JavaClass owningClass) {
this.owningClass = owningClass;
}
/**
* Returns the <code>JavaClass</code> which contains this field.
*
* @return <code>JavaClass</code> representing the owner of this <code>JavaField</code>.
*/
public JavaClass getOwningClass() {
return this.owningClass;
}
}