com.hazelcast.shaded.org.codehaus.janino.ReflectionIClass Maven / Gradle / Ivy
/*
* Janino - An embedded Java[TM] compiler
*
* Copyright (c) 2001-2010 Arno Unkrig. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.hazelcast.shaded.org.codehaus.janino;
import java.lang.annotation.Annotation;
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.Arrays;
import com.hazelcast.shaded.org.codehaus.commons.compiler.CompileException;
import com.hazelcast.shaded.org.codehaus.commons.compiler.InternalCompilerException;
import com.hazelcast.shaded.org.codehaus.commons.compiler.Location;
import com.hazelcast.shaded.org.codehaus.commons.nullanalysis.Nullable;
/**
* Wraps a {@link java.lang.Class} in an {@link com.hazelcast.shaded.org.codehaus.janino.IClass}.
*/
class ReflectionIClass extends IClass {
private final Class> clazz;
private final IClassLoader iClassLoader;
/**
* @param iClassLoader Required to load other {@link IClass}es on {@code get...()}
*/
ReflectionIClass(Class> clazz, IClassLoader iClassLoader) {
this.clazz = clazz;
clazz.getTypeParameters();
this.iClassLoader = iClassLoader;
}
@Override public ITypeVariable[]
getITypeVariables2() {
final TypeVariable>[] tps = this.clazz.getTypeParameters();
ITypeVariable[] result = new ITypeVariable[tps.length];
for (int i = 0; i < result.length; i++) result[i] = this.typeVariableToITypeVariable(tps[i]);
return result;
}
private ITypeVariable
typeVariableToITypeVariable(final TypeVariable> tv) {
return new ITypeVariable() {
@Override public String
getName() { return tv.getName(); }
@Override public ITypeVariableOrIClass[]
getBounds() throws CompileException {
IType[] tmp = ReflectionIClass.this.typesToITypes(tv.getBounds());
return (ITypeVariableOrIClass[]) Arrays.copyOf(tmp, tmp.length, ITypeVariableOrIClass[].class);
}
};
}
private IType[]
typesToITypes(Type[] types) throws CompileException {
IType[] result = new IType[types.length];
for (int i = 0; i < result.length; i++) result[i] = this.typeToIType(types[i]);
return result;
}
private IType
typeToIType(Type type) throws CompileException {
if (type instanceof Class) {
IClass iClass;
try {
iClass = this.iClassLoader.loadIClass(Descriptor.fromClassName(((Class>) type).getName()));
} catch (ClassNotFoundException cnfe) {
throw new CompileException("Loading \"" + type + "\"", null, cnfe);
}
if (iClass == null) throw new CompileException("Could not load \"" + type + "\"", null);
return iClass;
} else
if (type instanceof GenericArrayType) {
throw new AssertionError("NYI");
} else
if (type instanceof ParameterizedType) {
throw new AssertionError("NYI");
} else
if (type instanceof TypeVariable) {
throw new AssertionError("NYI");
} else
if (type instanceof WildcardType) {
throw new AssertionError("NYI");
} else
{
throw new AssertionError(type.getClass());
}
}
@Override protected IConstructor[]
getDeclaredIConstructors2() {
Constructor>[] constructors = this.clazz.getDeclaredConstructors();
IConstructor[] result = new IConstructor[constructors.length];
for (int i = 0; i < constructors.length; ++i) {
result[i] = new ReflectionIConstructor(constructors[i]);
}
return result;
}
@Override protected IMethod[]
getDeclaredIMethods2() {
Method[] methods = this.clazz.getDeclaredMethods();
if (methods.length == 0 && this.clazz.isArray()) {
// Arrays have ONE single method: "Object clone()".
return new IMethod[] { new IMethod() {
@Override public IAnnotation[] getAnnotations() { return new IAnnotation[0]; }
@Override public Access getAccess() { return Access.PUBLIC; }
@Override public boolean isStatic() { return false; }
@Override public boolean isAbstract() { return false; }
@Override public String getName() { return "clone"; }
@Override public IClass[] getParameterTypes2() { return new IClass[0]; }
@Override public boolean isVarargs() { return false; }
@Override public IClass[] getThrownExceptions2() { return new IClass[0]; }
@Override public IClass
getReturnType() { return ReflectionIClass.this.iClassLoader.TYPE_java_lang_Object; }
} };
}
return this.methodsToIMethods(methods);
}
@Override protected IField[]
getDeclaredIFields2() { return this.fieldsToIFields(this.clazz.getDeclaredFields()); }
@Override protected IClass[]
getDeclaredIClasses2() { return this.classesToIClasses(this.clazz.getDeclaredClasses()); }
@Override @Nullable protected IClass
getDeclaringIClass2() {
Class> declaringClass = this.clazz.getDeclaringClass();
return declaringClass == null ? null : this.classToIClass(declaringClass);
}
@Override @Nullable protected IClass
getOuterIClass2() throws CompileException {
if (Modifier.isStatic(this.clazz.getModifiers())) return null;
return this.getDeclaringIClass();
}
@Override @Nullable protected IClass
getSuperclass2() {
Class> superclass = this.clazz.getSuperclass();
return superclass == null ? null : this.classToIClass(superclass);
}
@Override @Nullable protected IClass
getComponentType2() {
Class> componentType = this.clazz.getComponentType();
return componentType == null ? null : this.classToIClass(componentType);
}
@Override protected IClass[] getInterfaces2() { return this.classesToIClasses(this.clazz.getInterfaces()); }
@Override protected String getDescriptor2() { return Descriptor.fromClassName(this.clazz.getName()); }
@Override public Access getAccess() { return ReflectionIClass.modifiers2Access(this.clazz.getModifiers()); }
@Override public boolean isFinal() { return Modifier.isFinal(this.clazz.getModifiers()); }
@Override public boolean isEnum() { return this.clazz.isEnum(); }
@Override public boolean isInterface() { return this.clazz.isInterface(); }
@Override public boolean isAbstract() { return Modifier.isAbstract(this.clazz.getModifiers()); }
@Override public boolean isArray() { return this.clazz.isArray(); }
@Override public boolean
isPrimitive() { return this.clazz.isPrimitive(); }
@Override public boolean
isPrimitiveNumeric() {
return (
this.clazz == byte.class
|| this.clazz == short.class
|| this.clazz == int.class
|| this.clazz == long.class
|| this.clazz == char.class
|| this.clazz == float.class
|| this.clazz == double.class
);
}
@Override public IAnnotation[]
getIAnnotations2() throws CompileException {
Annotation[] as = this.clazz.getAnnotations();
if (as.length == 0) return IClass.NO_ANNOTATIONS;
IAnnotation[] result = new IAnnotation[as.length];
for (int i = 0; i < as.length; i++) {
final Annotation a = as[i];
// Get annotation type IClass.
final Class extends Annotation> annotationType = a.annotationType();
final IClass annotationTypeIClass;
try {
annotationTypeIClass = ReflectionIClass.this.iClassLoader.loadIClass(
Descriptor.fromClassName(annotationType.getName())
);
} catch (ClassNotFoundException cnfe) {
throw new CompileException(
"Loading annotation type",
null, // location
cnfe
);
}
if (annotationTypeIClass == null) {
throw new CompileException("Could not load \"" + annotationType.getName() + "\"", null);
}
result[i] = new IAnnotation() {
@Override public IClass
getAnnotationType() { return annotationTypeIClass; }
@Override public Object
getElementValue(String name) throws CompileException {
try {
Object v = a.getClass().getMethod(name).invoke(a);
if (!Enum.class.isAssignableFrom(v.getClass())) return v;
Class> enumClass = v.getClass();
String enumConstantName = (String) enumClass.getMethod("name").invoke(v);
IClass enumIClass = ReflectionIClass.this.classToIClass(enumClass);
IField enumConstField = enumIClass.getDeclaredIField(enumConstantName);
if (enumConstField == null) {
throw new CompileException((
"Enum \""
+ enumIClass
+ "\" has no constant \""
+ enumConstantName
+ ""
), null);
}
return enumConstField;
} catch (NoSuchMethodException e) {
throw new CompileException(
"Annotation \"" + annotationType.getName() + "\" has no element \"" + name + "\"",
null
);
} catch (Exception e) {
throw new AssertionError(e);
}
}
@Override public String
toString() { return "@" + annotationTypeIClass; }
};
}
return result;
}
/**
* @return The underlying {@link Class java.lang.Class}
*/
public Class>
getClazz() { return this.clazz; }
/**
* @return E.g. {@code "int"}, {@code "int[][]"}, {@code "pkg1.pkg2.Outer$Inner[]"}
*/
@Override public String
toString() {
int brackets = 0;
Class> c = this.clazz;
while (c.isArray()) {
++brackets;
c = c.getComponentType();
}
String s = c.getName();
// Must not strip "java.lang.", because some pieces of code rely on "toString()" returning the COMPLETE
// qualified name.
// if (s.startsWith("java.lang.")) s = s.substring(10);
while (brackets-- > 0) s += "[]";
return s;
}
private
class ReflectionIConstructor extends IConstructor {
ReflectionIConstructor(Constructor> constructor) { this.constructor = constructor; }
// Implement IMember.
@Override public Access
getAccess() { return ReflectionIClass.modifiers2Access(this.constructor.getModifiers()); }
@Override public IAnnotation[]
getAnnotations() { return new IAnnotation[0]; }
@Override public boolean
isVarargs() {
// TRANSIENT is identical with VARARGS.
return Modifier.isTransient(this.constructor.getModifiers());
}
// Implement "IConstructor".
@Override public IClass[]
getParameterTypes2() throws CompileException {
IClass[] parameterTypes = ReflectionIClass.this.classesToIClasses(this.constructor.getParameterTypes());
// The JAVADOC of java.lang.reflect.Constructor does not document it, but "getParameterTypes()" includes
// the synthetic "enclosing instance" parameter.
IClass outerClass = ReflectionIClass.this.getOuterIClass();
if (outerClass != null) {
if (parameterTypes.length < 1) {
throw new CompileException(
"Constructor \"" + this.constructor + "\" lacks synthetic enclosing instance parameter",
null
);
}
if (parameterTypes[0] != outerClass) {
throw new CompileException((
"Enclosing instance parameter of constructor \""
+ this.constructor
+ "\" has wrong type -- \""
+ parameterTypes[0]
+ "\" vs. \""
+ outerClass
+ "\""
), null);
}
IClass[] tmp = new IClass[parameterTypes.length - 1];
System.arraycopy(parameterTypes, 1, tmp, 0, tmp.length);
parameterTypes = tmp;
}
return parameterTypes;
}
@Override public MethodDescriptor
getDescriptor2() {
Class>[] parameterTypes = this.constructor.getParameterTypes();
String[] parameterDescriptors = new String[parameterTypes.length];
for (int i = 0; i < parameterDescriptors.length; ++i) {
parameterDescriptors[i] = Descriptor.fromClassName(parameterTypes[i].getName());
}
return new MethodDescriptor(Descriptor.VOID, parameterDescriptors);
}
@Override public IClass[]
getThrownExceptions2() {
return ReflectionIClass.this.classesToIClasses(this.constructor.getExceptionTypes());
}
final Constructor> constructor;
}
public
class ReflectionIMethod extends IMethod {
ReflectionIMethod(Method method) { this.method = method; }
// Implement IMember.
@Override public Access
getAccess() { return ReflectionIClass.modifiers2Access(this.method.getModifiers()); }
@Override public IAnnotation[]
getAnnotations() { return new IAnnotation[0]; }
// Implement "IMethod".
@Override public String
getName() { return this.method.getName(); }
@Override public boolean
isVarargs() {
// VARARGS is identical with TRANSIENT.
return Modifier.isTransient(this.method.getModifiers());
}
@Override public IClass[]
getParameterTypes2() { return ReflectionIClass.this.classesToIClasses(this.method.getParameterTypes()); }
@Override public boolean
isStatic() { return Modifier.isStatic(this.method.getModifiers()); }
@Override public boolean
isAbstract() { return Modifier.isAbstract(this.method.getModifiers()); }
@Override public IClass
getReturnType() { return ReflectionIClass.this.classToIClass(this.method.getReturnType()); }
@Override public IClass[]
getThrownExceptions2() { return ReflectionIClass.this.classesToIClasses(this.method.getExceptionTypes()); }
private final Method method;
}
private
class ReflectionIField extends IField {
ReflectionIField(Field field) { this.field = field; }
// Implement IMember.
@Override public Access
getAccess() { return ReflectionIClass.modifiers2Access(this.field.getModifiers()); }
@Override public IAnnotation[]
getAnnotations() { return new IAnnotation[0]; }
// Implement "IField".
@Override public String
getName() { return this.field.getName(); }
@Override public boolean
isStatic() { return Modifier.isStatic(this.field.getModifiers()); }
@Override public IClass
getType() { return ReflectionIClass.this.classToIClass(this.field.getType()); }
@Override public String
toString() {
return Descriptor.toString(this.getDeclaringIClass().getDescriptor()) + "." + this.getName();
}
/**
* This implementation of {@link IClass.IField#getConstantValue()} is not completely correct:
*
* -
* It treats non-static fields as non-constant
*
* -
* Even fields with a non-constant initializer are identified as constant. (The value of that
* field may be different in a different JVM instance -- the classical example is {@link
* java.io.File#separator}.)
*
*
*
* Notice that enum constants are not constant expression (despite the similarity of names).
*
*/
@Override public Object
getConstantValue() throws CompileException {
int mod = this.field.getModifiers();
Class> clazz = this.field.getType();
if (
Modifier.isStatic(mod)
&& Modifier.isFinal(mod)
&& (clazz.isPrimitive() || clazz == String.class)
) {
try {
return this.field.get(null);
} catch (IllegalAccessException ex) {
throw new CompileException( // SUPPRESS CHECKSTYLE AvoidHidingCause
"Field \"" + this.field.getName() + "\" is not accessible",
(Location) null
);
}
}
return IClass.NOT_CONSTANT;
}
final Field field;
}
/**
* Loads {@link Class} through {@link IClassLoader} to ensure unique {@link IClass}es.
*/
private IClass
classToIClass(Class> c) {
IClass iClass;
try {
iClass = this.iClassLoader.loadIClass(Descriptor.fromClassName(c.getName()));
} catch (ClassNotFoundException ex) {
throw new InternalCompilerException("Loading IClass \"" + c.getName() + "\": " + ex);
}
if (iClass == null) {
throw new InternalCompilerException((
"Cannot load class \"" + c.getName() + "\" through the given ClassLoader"
));
}
return iClass;
}
/**
* @see #classToIClass(Class)
*/
private IClass[]
classesToIClasses(Class>[] cs) {
IClass[] result = new IClass[cs.length];
for (int i = 0; i < cs.length; ++i) result[i] = this.classToIClass(cs[i]);
return result;
}
private IMethod[]
methodsToIMethods(Method[] methods) {
IMethod[] result = new IMethod[methods.length];
for (int i = 0; i < result.length; i++) result[i] = new ReflectionIMethod(methods[i]);
return result;
}
private IField[]
fieldsToIFields(Field[] fields) {
IField[] result = new IField[fields.length];
for (int i = 0; i < fields.length; ++i) result[i] = new ReflectionIField(fields[i]);
return result;
}
private static Access
modifiers2Access(int modifiers) {
return (
Modifier.isPrivate(modifiers) ? Access.PRIVATE :
Modifier.isProtected(modifiers) ? Access.PROTECTED :
Modifier.isPublic(modifiers) ? Access.PUBLIC :
Access.DEFAULT
);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy