blob: d7c399c1203bac137b94a6981746cf9ddec49bae [file] [log] [blame]
/*
* Copyright (c) 2011, 2021 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.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.jaxb.javamodel.JavaAnnotation;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.JavaMethod;
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.JMethod;
import com.sun.codemodel.JType;
/**
* INTERNAL:
* <p>
* <b>Purpose:</b> <code>JavaMethod</code> implementation wrapping XJC's <code>JMethod</code>. Used when
* bootstrapping a <code>DynamicJAXBContext</code> from an XML Schema.
* </p>
*
* <p>
* <b>Responsibilities:</b>
* </p>
* <ul>
* <li>Provide <code>Method</code> information from the underlying <code>JMethod</code>.</li>
* </ul>
*
* @since EclipseLink 2.1
*
* @see org.eclipse.persistence.jaxb.javamodel.JavaMethod
*/
public class XJCJavaMethodImpl implements JavaMethod {
private JMethod xjcMethod;
private JCodeModel jCodeModel;
private DynamicClassLoader dynamicClassLoader;
private JavaClass owningClass;
/**
* Construct a new instance of <code>XJCJavaMethodImpl</code>.
*
* @param javaMethod - the XJC <code>JMethod</code> to be wrapped.
* @param codeModel - the XJC <code>JCodeModel</code> this method belongs to.
* @param loader - the <code>ClassLoader</code> used to bootstrap the <code>DynamicJAXBContext</code>.
* @param owner - the <code>JavaClass</code> this method belongs to.
*/
public XJCJavaMethodImpl(JMethod javaMethod, JCodeModel codeModel, DynamicClassLoader loader, JavaClass owner) {
this.xjcMethod = javaMethod;
this.jCodeModel = codeModel;
this.dynamicClassLoader = loader;
this.owningClass = owner;
}
/**
* If this <code>JavaMethod</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>.
*/
@Override
@SuppressWarnings("unchecked")
public JavaAnnotation getAnnotation(JavaClass aClass) {
if (aClass != null) {
Collection<JAnnotationUse> annotations = xjcMethod.annotations();
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>JavaMethod</code>.
*
* @return A <code>Collection</code> containing this <code>JavaMethod's</code> <code>JavaAnnotations</code>.
*/
@Override
@SuppressWarnings("unchecked")
public Collection<JavaAnnotation> getAnnotations() {
ArrayList<JavaAnnotation> annotationsList = new ArrayList<>();
Collection<JAnnotationUse> annotations = xjcMethod.annotations();
for (JAnnotationUse annotationUse : annotations) {
XJCJavaAnnotationImpl xjcAnnotation = new XJCJavaAnnotationImpl(annotationUse, dynamicClassLoader);
annotationsList.add(xjcAnnotation);
}
return annotationsList;
}
/**
* Returns the name of this <code>JavaMethod</code>.
*
* @return the <code>String</code> name of this <code>JavaMethod</code>.
*/
@Override
public String getName() {
return xjcMethod.name();
}
/**
* Returns the array of parameters for this <code>JavaMethod</code>.
*
* @return a <code>JavaClass[]</code> representing the argument types for this method.
*/
@Override
public JavaClass[] getParameterTypes() {
JType[] params = xjcMethod.listParamTypes();
JavaClass[] paramArray = new JavaClass[params.length];
for (int i = 0; i < params.length; i++) {
if (((XJCJavaClassImpl) getOwningClass()).getJavaModel() != null) {
paramArray[i] = ((XJCJavaClassImpl) getOwningClass()).getJavaModel().getClass(params[i].fullName());
} else {
paramArray[i] = new XJCJavaClassImpl((JDefinedClass) params[i], jCodeModel, dynamicClassLoader);
}
}
return paramArray;
}
/**
* Returns this <code>JavaMethod's</code> return type.
*
* @return a <code>JavaClass</code> representing the return type of this method.
*/
public JavaClass getResolvedType() {
if (((XJCJavaClassImpl) getOwningClass()).getJavaModel() != null) {
return ((XJCJavaClassImpl) getOwningClass()).getJavaModel().getClass(xjcMethod.type().fullName());
}
try {
return new XJCJavaClassImpl(jCodeModel._class(xjcMethod.type().fullName()), jCodeModel, dynamicClassLoader);
} catch (JClassAlreadyExistsException ex) {
return new XJCJavaClassImpl(jCodeModel._getClass(xjcMethod.type().fullName()), jCodeModel, dynamicClassLoader);
}
}
/**
* Returns this <code>JavaMethod's</code> return type.
*
* @return a <code>JavaClass</code> representing the return type of this method.
*/
@Override
@SuppressWarnings("unchecked")
public JavaClass getReturnType() {
JType type = xjcMethod.type();
JavaClass returnClass = null;
if (((XJCJavaClassImpl) getOwningClass()).getJavaModel() != null) {
returnClass = ((XJCJavaClassImpl) getOwningClass()).getJavaModel().getClass(type.fullName());
} else {
try {
returnClass = new XJCJavaClassImpl(jCodeModel._class(type.fullName()), jCodeModel, dynamicClassLoader);
} catch (JClassAlreadyExistsException ex) {
returnClass = new XJCJavaClassImpl(jCodeModel._getClass(type.fullName()), jCodeModel, dynamicClassLoader);
}
}
if (type instanceof JClass) {
JClass jcl = (JClass) type;
if (jcl.isParameterized()) {
List<JClass> args = jcl.getTypeParameters();
JClass arg = args.get(0);
JavaClass argClass = ((XJCJavaClassImpl) getOwningClass()).getJavaModel().getClass(arg.fullName());
((XJCJavaClassImpl) returnClass).setActualTypeArgument(argClass);
}
}
return returnClass;
}
/**
* Indicates if this <code>JavaMethod</code> has actual type arguments, i.e. is a
* parameterized type (for example, <code>List&lt;Employee</code>).
*
* @return <code>true</code> if this <code>JavaClass</code> is parameterized, otherwise <code>false</code>.
*/
public boolean hasActualTypeArguments() {
try {
JavaClass[] allParams = getParameterTypes();
for (JavaClass type : allParams) {
Class<?> paramClass = Class.forName(type.getPackageName() + "." + type.getName());
if (paramClass.getConstructor().newInstance() instanceof ParameterizedType) {
return true;
}
}
return false;
} catch (Exception e) {
return false;
}
}
/**
* Not supported.
*/
public Collection<Object> getActualTypeArguments() {
throw new UnsupportedOperationException("getActualTypeArguments");
}
/**
* Returns the Java language modifiers for this <code>JavaMethod</code>, encoded in an integer.
*
* @return the <code>int</code> representing the modifiers for this method.
*
* @see java.lang.reflect.Modifier
*/
@Override
public int getModifiers() {
return xjcMethod.mods().getValue();
}
/**
* Indicates if this <code>JavaMethod</code> is <code>abstract</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>abstract</code>, otherwise <code>false</code>.
*/
@Override
public boolean isAbstract() {
return Modifier.isAbstract(getModifiers());
}
/**
* Indicates if this <code>JavaMethod</code> is <code>private</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>private</code>, otherwise <code>false</code>.
*/
@Override
public boolean isPrivate() {
return Modifier.isPrivate(getModifiers());
}
/**
* Indicates if this <code>JavaMethod</code> is <code>protected</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>protected</code>, otherwise <code>false</code>.
*/
@Override
public boolean isProtected() {
return Modifier.isProtected(getModifiers());
}
/**
* Indicates if this <code>JavaMethod</code> is <code>public</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>public</code>, otherwise <code>false</code>.
*/
@Override
public boolean isPublic() {
return Modifier.isPublic(getModifiers());
}
/**
* Indicates if this <code>JavaMethod</code> is <code>static</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>static</code>, otherwise <code>false</code>.
*/
@Override
public boolean isStatic() {
return Modifier.isStatic(getModifiers());
}
/**
* Indicates if this <code>JavaMethod</code> is <code>final</code>.
*
* @return <code>true</code> if this <code>JavaMethod</code> is <code>final</code>, otherwise <code>false</code>.
*/
@Override
public boolean isFinal() {
return Modifier.isFinal(getModifiers());
}
/**
* Not supported.
*/
@Override
public boolean isSynthetic() {
return false;
}
/**
* Not supported.
*/
@Override
public JavaAnnotation getDeclaredAnnotation(JavaClass arg0) {
throw new UnsupportedOperationException("getDeclaredAnnotation");
}
/**
* Not supported.
*/
@Override
public Collection<JavaAnnotation> getDeclaredAnnotations() {
throw new UnsupportedOperationException("getDeclaredAnnotations");
}
/**
* Returns the <code>JavaClass</code> which contains this method.
*
* @return <code>JavaClass</code> representing the owner of this <code>JavaMethod</code>.
*/
@Override
public JavaClass getOwningClass() {
return owningClass;
}
/**
* Set the <code>JavaClass</code> which contains this method.
*
* @param owningClass the <code>JavaClass</code> representing the owner of this <code>JavaMethod</code>.
*/
public void setOwningClass(JavaClass owningClass) {
this.owningClass = owningClass;
}
/**
* Not supported.
*/
@Override
public boolean isBridge() {
return false;
}
}