Painless: Clean up add methods in PainlessLookup (#32258)
This is largely mechanical change that cleans up the addConstructor, addMethod, and addFields methods in PainlessLookup. Changes include renamed variables, better error messages, and some minor code movement to make it more maintainable long term.
This commit is contained in:
parent
33f11e637d
commit
d3c4904fa3
|
@ -24,10 +24,12 @@ import org.elasticsearch.painless.spi.WhitelistClass;
|
|||
import org.elasticsearch.painless.spi.WhitelistConstructor;
|
||||
import org.elasticsearch.painless.spi.WhitelistField;
|
||||
import org.elasticsearch.painless.spi.WhitelistMethod;
|
||||
import org.objectweb.asm.Type;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
@ -38,8 +40,13 @@ import java.util.Objects;
|
|||
import java.util.Stack;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_TYPE_NAME;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.CONSTRUCTOR_NAME;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.DEF_CLASS_NAME;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessFieldKey;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.buildPainlessMethodKey;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToCanonicalTypeName;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typeToJavaType;
|
||||
import static org.elasticsearch.painless.lookup.PainlessLookupUtility.typesToCanonicalTypeNames;
|
||||
|
||||
public class PainlessLookupBuilder {
|
||||
|
||||
|
@ -123,17 +130,17 @@ public class PainlessLookupBuilder {
|
|||
private final List<Whitelist> whitelists;
|
||||
|
||||
private final Map<String, Class<?>> canonicalClassNamesToClasses;
|
||||
private final Map<Class<?>, PainlessClassBuilder> classesToPainlessClasses;
|
||||
private final Map<Class<?>, PainlessClassBuilder> classesToPainlessClassBuilders;
|
||||
|
||||
public PainlessLookupBuilder(List<Whitelist> whitelists) {
|
||||
this.whitelists = whitelists;
|
||||
|
||||
canonicalClassNamesToClasses = new HashMap<>();
|
||||
classesToPainlessClasses = new HashMap<>();
|
||||
classesToPainlessClassBuilders = new HashMap<>();
|
||||
|
||||
canonicalClassNamesToClasses.put(DEF_TYPE_NAME, def.class);
|
||||
classesToPainlessClasses.put(def.class,
|
||||
new PainlessClassBuilder(DEF_TYPE_NAME, Object.class, Type.getType(Object.class)));
|
||||
canonicalClassNamesToClasses.put(DEF_CLASS_NAME, def.class);
|
||||
classesToPainlessClassBuilders.put(def.class,
|
||||
new PainlessClassBuilder(DEF_CLASS_NAME, Object.class, org.objectweb.asm.Type.getType(Object.class)));
|
||||
}
|
||||
|
||||
private Class<?> canonicalTypeNameToType(String canonicalTypeName) {
|
||||
|
@ -141,7 +148,7 @@ public class PainlessLookupBuilder {
|
|||
}
|
||||
|
||||
private void validateType(Class<?> type) {
|
||||
PainlessLookupUtility.validateType(type, classesToPainlessClasses.keySet());
|
||||
PainlessLookupUtility.validateType(type, classesToPainlessClassBuilders.keySet());
|
||||
}
|
||||
|
||||
public void addPainlessClass(ClassLoader classLoader, String javaClassName, boolean importClassName) {
|
||||
|
@ -174,10 +181,10 @@ public class PainlessLookupBuilder {
|
|||
Objects.requireNonNull(clazz);
|
||||
|
||||
if (clazz == def.class) {
|
||||
throw new IllegalArgumentException("cannot add reserved class [" + DEF_TYPE_NAME + "]");
|
||||
throw new IllegalArgumentException("cannot add reserved class [" + DEF_CLASS_NAME + "]");
|
||||
}
|
||||
|
||||
String canonicalClassName = clazz.getCanonicalName();
|
||||
String canonicalClassName = typeToCanonicalTypeName(clazz);
|
||||
|
||||
if (clazz.isArray()) {
|
||||
throw new IllegalArgumentException("cannot add array type [" + canonicalClassName + "] as a class");
|
||||
|
@ -187,13 +194,14 @@ public class PainlessLookupBuilder {
|
|||
throw new IllegalArgumentException("invalid class name [" + canonicalClassName + "]");
|
||||
}
|
||||
|
||||
PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClasses.get(clazz);
|
||||
PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClassBuilders.get(clazz);
|
||||
|
||||
if (existingPainlessClassBuilder == null) {
|
||||
PainlessClassBuilder painlessClassBuilder = new PainlessClassBuilder(canonicalClassName, clazz, Type.getType(clazz));
|
||||
PainlessClassBuilder painlessClassBuilder =
|
||||
new PainlessClassBuilder(canonicalClassName, clazz, org.objectweb.asm.Type.getType(clazz));
|
||||
|
||||
canonicalClassNamesToClasses.put(canonicalClassName, clazz);
|
||||
classesToPainlessClasses.put(clazz, painlessClassBuilder);
|
||||
classesToPainlessClassBuilders.put(clazz, painlessClassBuilder);
|
||||
} else if (existingPainlessClassBuilder.clazz.equals(clazz) == false) {
|
||||
throw new IllegalArgumentException("class [" + canonicalClassName + "] " +
|
||||
"cannot represent multiple java classes with the same name from different class loaders");
|
||||
|
@ -207,308 +215,459 @@ public class PainlessLookupBuilder {
|
|||
throw new IllegalArgumentException("must use only_fqn parameter on class [" + canonicalClassName + "] with no package");
|
||||
}
|
||||
} else {
|
||||
Class<?> importedPainlessType = canonicalClassNamesToClasses.get(importedCanonicalClassName);
|
||||
Class<?> importedPainlessClass = canonicalClassNamesToClasses.get(importedCanonicalClassName);
|
||||
|
||||
if (importedPainlessType == null) {
|
||||
if (importedPainlessClass == null) {
|
||||
if (importClassName) {
|
||||
if (existingPainlessClassBuilder != null) {
|
||||
throw new IllegalArgumentException(
|
||||
"inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
|
||||
throw new IllegalArgumentException("inconsistent only_fqn parameters found for class [" + canonicalClassName + "]");
|
||||
}
|
||||
|
||||
canonicalClassNamesToClasses.put(importedCanonicalClassName, clazz);
|
||||
}
|
||||
} else if (importedPainlessType.equals(clazz) == false) {
|
||||
throw new IllegalArgumentException("painless type [" + importedCanonicalClassName + "] illegally represents multiple " +
|
||||
"java types [" + clazz.getCanonicalName() + "] and [" + importedPainlessType.getCanonicalName() + "]");
|
||||
} else if (importedPainlessClass.equals(clazz) == false) {
|
||||
throw new IllegalArgumentException("imported class [" + importedCanonicalClassName + "] cannot represent multiple " +
|
||||
"classes [" + canonicalClassName + "] and [" + typeToCanonicalTypeName(importedPainlessClass) + "]");
|
||||
} else if (importClassName == false) {
|
||||
throw new IllegalArgumentException("inconsistent only_fqn parameters found for painless type [" + canonicalClassName + "]");
|
||||
throw new IllegalArgumentException("inconsistent only_fqn parameters found for class [" + canonicalClassName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addConstructor(String ownerStructName, WhitelistConstructor whitelistConstructor) {
|
||||
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
|
||||
public void addPainlessConstructor(String targetCanonicalClassName, List<String> typeNameParameters) {
|
||||
Objects.requireNonNull(targetCanonicalClassName);
|
||||
Objects.requireNonNull(typeNameParameters);
|
||||
|
||||
if (ownerStruct == null) {
|
||||
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for constructor with " +
|
||||
"parameters " + whitelistConstructor.painlessParameterTypeNames);
|
||||
Class<?> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
|
||||
|
||||
if (targetClass == null) {
|
||||
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found" +
|
||||
"for constructor [[" + targetCanonicalClassName + "], " + typeNameParameters + "]");
|
||||
}
|
||||
|
||||
List<Class<?>> painlessParametersTypes = new ArrayList<>(whitelistConstructor.painlessParameterTypeNames.size());
|
||||
Class<?>[] javaClassParameters = new Class<?>[whitelistConstructor.painlessParameterTypeNames.size()];
|
||||
|
||||
for (int parameterCount = 0; parameterCount < whitelistConstructor.painlessParameterTypeNames.size(); ++parameterCount) {
|
||||
String painlessParameterTypeName = whitelistConstructor.painlessParameterTypeNames.get(parameterCount);
|
||||
List<Class<?>> typeParameters = new ArrayList<>(typeNameParameters.size());
|
||||
|
||||
for (String typeNameParameter : typeNameParameters) {
|
||||
try {
|
||||
Class<?> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
|
||||
|
||||
painlessParametersTypes.add(painlessParameterClass);
|
||||
javaClassParameters[parameterCount] = PainlessLookupUtility.typeToJavaType(painlessParameterClass);
|
||||
Class<?> typeParameter = canonicalTypeNameToType(typeNameParameter);
|
||||
typeParameters.add(typeParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("struct not defined for constructor parameter [" + painlessParameterTypeName + "] " +
|
||||
"with owner struct [" + ownerStructName + "] and constructor parameters " +
|
||||
whitelistConstructor.painlessParameterTypeNames, iae);
|
||||
throw new IllegalArgumentException("type parameter [" + typeNameParameter + "] not found " +
|
||||
"for constructor [[" + targetCanonicalClassName + "], " + typeNameParameters + "]", iae);
|
||||
}
|
||||
}
|
||||
|
||||
java.lang.reflect.Constructor<?> javaConstructor;
|
||||
addPainlessConstructor(targetClass, typeParameters);
|
||||
}
|
||||
|
||||
try {
|
||||
javaConstructor = ownerStruct.clazz.getConstructor(javaClassParameters);
|
||||
} catch (NoSuchMethodException exception) {
|
||||
throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " +
|
||||
" with constructor parameters " + whitelistConstructor.painlessParameterTypeNames, exception);
|
||||
public void addPainlessConstructor(Class<?> targetClass, List<Class<?>> typeParameters) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(typeParameters);
|
||||
|
||||
if (targetClass == def.class) {
|
||||
throw new IllegalArgumentException("cannot add constructor to reserved class [" + DEF_CLASS_NAME + "]");
|
||||
}
|
||||
|
||||
String painlessMethodKey = buildPainlessMethodKey("<init>", whitelistConstructor.painlessParameterTypeNames.size());
|
||||
PainlessMethod painlessConstructor = ownerStruct.constructors.get(painlessMethodKey);
|
||||
String targetCanonicalClassName = targetClass.getCanonicalName();
|
||||
PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
|
||||
|
||||
if (painlessClassBuilder == null) {
|
||||
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found" +
|
||||
"for constructor [[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
|
||||
}
|
||||
|
||||
int typeParametersSize = typeParameters.size();
|
||||
List<Class<?>> javaTypeParameters = new ArrayList<>(typeParametersSize);
|
||||
|
||||
for (Class<?> typeParameter : typeParameters) {
|
||||
try {
|
||||
validateType(typeParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] not found " +
|
||||
"for constructor [[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "]", iae);
|
||||
}
|
||||
|
||||
javaTypeParameters.add(typeToJavaType(typeParameter));
|
||||
}
|
||||
|
||||
Constructor<?> javaConstructor;
|
||||
|
||||
try {
|
||||
javaConstructor = targetClass.getConstructor(javaTypeParameters.toArray(new Class<?>[typeParametersSize]));
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException("constructor reflection object " +
|
||||
"[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", nsme);
|
||||
}
|
||||
|
||||
String painlessMethodKey = buildPainlessMethodKey(CONSTRUCTOR_NAME, typeParametersSize);
|
||||
PainlessMethod painlessConstructor = painlessClassBuilder.constructors.get(painlessMethodKey);
|
||||
|
||||
if (painlessConstructor == null) {
|
||||
org.objectweb.asm.commons.Method asmConstructor = org.objectweb.asm.commons.Method.getMethod(javaConstructor);
|
||||
MethodHandle javaHandle;
|
||||
MethodHandle methodHandle;
|
||||
|
||||
try {
|
||||
javaHandle = MethodHandles.publicLookup().in(ownerStruct.clazz).unreflectConstructor(javaConstructor);
|
||||
} catch (IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " +
|
||||
" with constructor parameters " + whitelistConstructor.painlessParameterTypeNames);
|
||||
methodHandle = MethodHandles.publicLookup().in(targetClass).unreflectConstructor(javaConstructor);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException("constructor method handle " +
|
||||
"[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
|
||||
}
|
||||
|
||||
painlessConstructor = painlessMethodCache.computeIfAbsent(
|
||||
new PainlessMethodCacheKey(ownerStruct.clazz, "<init>", painlessParametersTypes),
|
||||
key -> new PainlessMethod("<init>", ownerStruct.clazz, null, void.class, painlessParametersTypes,
|
||||
asmConstructor, javaConstructor.getModifiers(), javaHandle));
|
||||
ownerStruct.constructors.put(painlessMethodKey, painlessConstructor);
|
||||
} else if (painlessConstructor.arguments.equals(painlessParametersTypes) == false){
|
||||
throw new IllegalArgumentException(
|
||||
"illegal duplicate constructors [" + painlessMethodKey + "] found within the struct [" + ownerStruct.name + "] " +
|
||||
"with parameters " + painlessParametersTypes + " and " + painlessConstructor.arguments);
|
||||
new PainlessMethodCacheKey(targetClass, CONSTRUCTOR_NAME, typeParameters),
|
||||
key -> new PainlessMethod(CONSTRUCTOR_NAME, targetClass, null, void.class, typeParameters,
|
||||
asmConstructor, javaConstructor.getModifiers(), methodHandle)
|
||||
);
|
||||
|
||||
painlessClassBuilder.constructors.put(painlessMethodKey, painlessConstructor);
|
||||
} else if (painlessConstructor.arguments.equals(typeParameters) == false){
|
||||
throw new IllegalArgumentException("cannot have constructors " +
|
||||
"[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(typeParameters) + "] and " +
|
||||
"[[" + targetCanonicalClassName + "], " + typesToCanonicalTypeNames(painlessConstructor.arguments) + "] " +
|
||||
"with the same arity and different type parameters");
|
||||
}
|
||||
}
|
||||
|
||||
private void addMethod(ClassLoader whitelistClassLoader, String ownerStructName, WhitelistMethod whitelistMethod) {
|
||||
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
|
||||
public void addPainlessMethod(ClassLoader classLoader, String targetCanonicalClassName, String augmentedCanonicalClassName,
|
||||
String methodName, String returnCanonicalTypeName, List<String> typeNameParameters) {
|
||||
|
||||
if (ownerStruct == null) {
|
||||
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
|
||||
"name [" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
|
||||
Objects.requireNonNull(classLoader);
|
||||
Objects.requireNonNull(targetCanonicalClassName);
|
||||
Objects.requireNonNull(methodName);
|
||||
Objects.requireNonNull(returnCanonicalTypeName);
|
||||
Objects.requireNonNull(typeNameParameters);
|
||||
|
||||
Class<?> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
|
||||
|
||||
if (targetClass == null) {
|
||||
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]");
|
||||
}
|
||||
|
||||
if (METHOD_NAME_PATTERN.matcher(whitelistMethod.javaMethodName).matches() == false) {
|
||||
throw new IllegalArgumentException("invalid method name" +
|
||||
" [" + whitelistMethod.javaMethodName + "] for owner struct [" + ownerStructName + "].");
|
||||
}
|
||||
Class<?> augmentedClass = null;
|
||||
|
||||
Class<?> javaAugmentedClass;
|
||||
|
||||
if (whitelistMethod.javaAugmentedClassName != null) {
|
||||
if (augmentedCanonicalClassName != null) {
|
||||
try {
|
||||
javaAugmentedClass = Class.forName(whitelistMethod.javaAugmentedClassName, true, whitelistClassLoader);
|
||||
augmentedClass = Class.forName(augmentedCanonicalClassName, true, classLoader);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
throw new IllegalArgumentException("augmented class [" + whitelistMethod.javaAugmentedClassName + "] " +
|
||||
"not found for method with name [" + whitelistMethod.javaMethodName + "] " +
|
||||
"and parameters " + whitelistMethod.painlessParameterTypeNames, cnfe);
|
||||
throw new IllegalArgumentException("augmented class [" + augmentedCanonicalClassName + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", cnfe);
|
||||
}
|
||||
} else {
|
||||
javaAugmentedClass = null;
|
||||
}
|
||||
|
||||
int augmentedOffset = javaAugmentedClass == null ? 0 : 1;
|
||||
|
||||
List<Class<?>> painlessParametersTypes = new ArrayList<>(whitelistMethod.painlessParameterTypeNames.size());
|
||||
Class<?>[] javaClassParameters = new Class<?>[whitelistMethod.painlessParameterTypeNames.size() + augmentedOffset];
|
||||
|
||||
if (javaAugmentedClass != null) {
|
||||
javaClassParameters[0] = ownerStruct.clazz;
|
||||
}
|
||||
|
||||
for (int parameterCount = 0; parameterCount < whitelistMethod.painlessParameterTypeNames.size(); ++parameterCount) {
|
||||
String painlessParameterTypeName = whitelistMethod.painlessParameterTypeNames.get(parameterCount);
|
||||
List<Class<?>> typeParameters = new ArrayList<>(typeNameParameters.size());
|
||||
|
||||
for (String typeNameParameter : typeNameParameters) {
|
||||
try {
|
||||
Class<?> painlessParameterClass = canonicalTypeNameToType(painlessParameterTypeName);
|
||||
|
||||
painlessParametersTypes.add(painlessParameterClass);
|
||||
javaClassParameters[parameterCount + augmentedOffset] =
|
||||
PainlessLookupUtility.typeToJavaType(painlessParameterClass);
|
||||
Class<?> typeParameter = canonicalTypeNameToType(typeNameParameter);
|
||||
typeParameters.add(typeParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("struct not defined for method parameter [" + painlessParameterTypeName + "] " +
|
||||
"with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
|
||||
"and parameters " + whitelistMethod.painlessParameterTypeNames, iae);
|
||||
throw new IllegalArgumentException("parameter type [" + typeNameParameter + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", iae);
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> javaImplClass = javaAugmentedClass == null ? ownerStruct.clazz : javaAugmentedClass;
|
||||
java.lang.reflect.Method javaMethod;
|
||||
Class<?> returnType;
|
||||
|
||||
try {
|
||||
javaMethod = javaImplClass.getMethod(whitelistMethod.javaMethodName, javaClassParameters);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException("method with name [" + whitelistMethod.javaMethodName + "] " +
|
||||
"and parameters " + whitelistMethod.painlessParameterTypeNames + " not found for class [" +
|
||||
javaImplClass.getName() + "]", nsme);
|
||||
}
|
||||
|
||||
Class<?> painlessReturnClass;
|
||||
|
||||
try {
|
||||
painlessReturnClass = canonicalTypeNameToType(whitelistMethod.painlessReturnTypeName);
|
||||
returnType = canonicalTypeNameToType(returnCanonicalTypeName);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("struct not defined for return type [" + whitelistMethod.painlessReturnTypeName + "] " +
|
||||
"with owner struct [" + ownerStructName + "] and method with name [" + whitelistMethod.javaMethodName + "] " +
|
||||
"and parameters " + whitelistMethod.painlessParameterTypeNames, iae);
|
||||
throw new IllegalArgumentException("parameter type [" + returnCanonicalTypeName + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typeNameParameters + "]", iae);
|
||||
}
|
||||
|
||||
if (javaMethod.getReturnType() != PainlessLookupUtility.typeToJavaType(painlessReturnClass)) {
|
||||
throw new IllegalArgumentException("specified return type class [" + painlessReturnClass + "] " +
|
||||
"does not match the return type class [" + javaMethod.getReturnType() + "] for the " +
|
||||
"method with name [" + whitelistMethod.javaMethodName + "] " +
|
||||
"and parameters " + whitelistMethod.painlessParameterTypeNames);
|
||||
addPainlessMethod(targetClass, augmentedClass, methodName, returnType, typeParameters);
|
||||
}
|
||||
|
||||
public void addPainlessMethod(Class<?> targetClass, Class<?> augmentedClass, String methodName,
|
||||
Class<?> returnType, List<Class<?>> typeParameters) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(methodName);
|
||||
Objects.requireNonNull(returnType);
|
||||
Objects.requireNonNull(typeParameters);
|
||||
|
||||
if (targetClass == def.class) {
|
||||
throw new IllegalArgumentException("cannot add method to reserved class [" + DEF_CLASS_NAME + "]");
|
||||
}
|
||||
|
||||
String painlessMethodKey =
|
||||
buildPainlessMethodKey(whitelistMethod.javaMethodName, whitelistMethod.painlessParameterTypeNames.size());
|
||||
String targetCanonicalClassName = typeToCanonicalTypeName(targetClass);
|
||||
|
||||
if (javaAugmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) {
|
||||
PainlessMethod painlessMethod = ownerStruct.staticMethods.get(painlessMethodKey);
|
||||
if (METHOD_NAME_PATTERN.matcher(methodName).matches() == false) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid method name [" + methodName + "] for target class [" + targetCanonicalClassName + "].");
|
||||
}
|
||||
|
||||
if (painlessMethod == null) {
|
||||
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
|
||||
MethodHandle javaMethodHandle;
|
||||
PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
|
||||
|
||||
try {
|
||||
javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod);
|
||||
} catch (IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("method handle not found for method with name " +
|
||||
"[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
|
||||
}
|
||||
if (painlessClassBuilder == null) {
|
||||
throw new IllegalArgumentException("target class [" + targetCanonicalClassName + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]");
|
||||
}
|
||||
|
||||
painlessMethod = painlessMethodCache.computeIfAbsent(
|
||||
new PainlessMethodCacheKey(ownerStruct.clazz, whitelistMethod.javaMethodName, painlessParametersTypes),
|
||||
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, null, painlessReturnClass,
|
||||
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
|
||||
ownerStruct.staticMethods.put(painlessMethodKey, painlessMethod);
|
||||
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn == painlessReturnClass &&
|
||||
painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
|
||||
throw new IllegalArgumentException("illegal duplicate static methods [" + painlessMethodKey + "] " +
|
||||
"found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " +
|
||||
"return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " +
|
||||
"and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments);
|
||||
int typeParametersSize = typeParameters.size();
|
||||
int augmentedParameterOffset = augmentedClass == null ? 0 : 1;
|
||||
List<Class<?>> javaTypeParameters = new ArrayList<>(typeParametersSize + augmentedParameterOffset);
|
||||
|
||||
if (augmentedClass != null) {
|
||||
javaTypeParameters.add(targetClass);
|
||||
}
|
||||
|
||||
for (Class<?> typeParameter : typeParameters) {
|
||||
try {
|
||||
validateType(typeParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] " +
|
||||
"not found for method [[" + targetCanonicalClassName + "], [" + methodName + "], " +
|
||||
typesToCanonicalTypeNames(typeParameters) + "]", iae);
|
||||
}
|
||||
|
||||
javaTypeParameters.add(typeToJavaType(typeParameter));
|
||||
}
|
||||
|
||||
try {
|
||||
validateType(returnType);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(returnType) + "] not found for method " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "]", iae);
|
||||
}
|
||||
|
||||
Method javaMethod;
|
||||
|
||||
if (augmentedClass == null) {
|
||||
try {
|
||||
javaMethod = targetClass.getMethod(methodName, javaTypeParameters.toArray(new Class<?>[typeParametersSize]));
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException("method reflection object [[" + targetCanonicalClassName + "], " +
|
||||
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", nsme);
|
||||
}
|
||||
} else {
|
||||
PainlessMethod painlessMethod = ownerStruct.methods.get(painlessMethodKey);
|
||||
try {
|
||||
javaMethod = augmentedClass.getMethod(methodName, javaTypeParameters.toArray(new Class<?>[typeParametersSize]));
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
throw new IllegalArgumentException("method reflection object [[" + targetCanonicalClassName + "], " +
|
||||
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
|
||||
"with augmented target class [" + typeToCanonicalTypeName(augmentedClass) + "]", nsme);
|
||||
}
|
||||
}
|
||||
|
||||
if (javaMethod.getReturnType() != typeToJavaType(returnType)) {
|
||||
throw new IllegalArgumentException("return type [" + typeToCanonicalTypeName(javaMethod.getReturnType()) + "] " +
|
||||
"does not match the specified returned type [" + typeToCanonicalTypeName(returnType) + "] " +
|
||||
"for method [[" + targetClass.getCanonicalName() + "], [" + methodName + "], " +
|
||||
typesToCanonicalTypeNames(typeParameters) + "]");
|
||||
}
|
||||
|
||||
String painlessMethodKey = buildPainlessMethodKey(methodName, typeParametersSize);
|
||||
|
||||
if (augmentedClass == null && Modifier.isStatic(javaMethod.getModifiers())) {
|
||||
PainlessMethod painlessMethod = painlessClassBuilder.staticMethods.get(painlessMethodKey);
|
||||
|
||||
if (painlessMethod == null) {
|
||||
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
|
||||
MethodHandle javaMethodHandle;
|
||||
|
||||
try {
|
||||
javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod);
|
||||
} catch (IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("method handle not found for method with name " +
|
||||
"[" + whitelistMethod.javaMethodName + "] and parameters " + whitelistMethod.painlessParameterTypeNames);
|
||||
javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException("static method handle [[" + targetClass.getCanonicalName() + "], " +
|
||||
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
|
||||
}
|
||||
|
||||
painlessMethod = painlessMethodCache.computeIfAbsent(
|
||||
new PainlessMethodCacheKey(ownerStruct.clazz, whitelistMethod.javaMethodName, painlessParametersTypes),
|
||||
key -> new PainlessMethod(whitelistMethod.javaMethodName, ownerStruct.clazz, javaAugmentedClass, painlessReturnClass,
|
||||
painlessParametersTypes, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
|
||||
ownerStruct.methods.put(painlessMethodKey, painlessMethod);
|
||||
} else if ((painlessMethod.name.equals(whitelistMethod.javaMethodName) && painlessMethod.rtn.equals(painlessReturnClass) &&
|
||||
painlessMethod.arguments.equals(painlessParametersTypes)) == false) {
|
||||
throw new IllegalArgumentException("illegal duplicate member methods [" + painlessMethodKey + "] " +
|
||||
"found within the struct [" + ownerStruct.name + "] with name [" + whitelistMethod.javaMethodName + "], " +
|
||||
"return types [" + painlessReturnClass + "] and [" + painlessMethod.rtn + "], " +
|
||||
"and parameters " + painlessParametersTypes + " and " + painlessMethod.arguments);
|
||||
new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
|
||||
key -> new PainlessMethod(methodName, targetClass, null, returnType,
|
||||
typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
|
||||
|
||||
painlessClassBuilder.staticMethods.put(painlessMethodKey, painlessMethod);
|
||||
} else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
|
||||
painlessMethod.arguments.equals(typeParameters)) == false) {
|
||||
throw new IllegalArgumentException("cannot have static methods " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
|
||||
"[" + typeToCanonicalTypeName(returnType) + "], " +
|
||||
typesToCanonicalTypeNames(typeParameters) + "] and " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
|
||||
"[" + typeToCanonicalTypeName(painlessMethod.rtn) + "], " +
|
||||
typesToCanonicalTypeNames(painlessMethod.arguments) + "] " +
|
||||
"with the same arity and different return type or type parameters");
|
||||
}
|
||||
} else {
|
||||
PainlessMethod painlessMethod = painlessClassBuilder.staticMethods.get(painlessMethodKey);
|
||||
|
||||
if (painlessMethod == null) {
|
||||
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
|
||||
MethodHandle javaMethodHandle;
|
||||
|
||||
if (augmentedClass == null) {
|
||||
try {
|
||||
javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
|
||||
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
javaMethodHandle = MethodHandles.publicLookup().in(augmentedClass).unreflect(javaMethod);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
|
||||
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
|
||||
"with augmented target class [" + typeToCanonicalTypeName(augmentedClass) + "]", iae);
|
||||
}
|
||||
}
|
||||
|
||||
painlessMethod = painlessMethodCache.computeIfAbsent(
|
||||
new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
|
||||
key -> new PainlessMethod(methodName, targetClass, augmentedClass, returnType,
|
||||
typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle));
|
||||
|
||||
painlessClassBuilder.methods.put(painlessMethodKey, painlessMethod);
|
||||
} else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
|
||||
painlessMethod.arguments.equals(typeParameters)) == false) {
|
||||
throw new IllegalArgumentException("cannot have methods " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
|
||||
"[" + typeToCanonicalTypeName(returnType) + "], " +
|
||||
typesToCanonicalTypeNames(typeParameters) + "] and " +
|
||||
"[[" + targetCanonicalClassName + "], [" + methodName + "], " +
|
||||
"[" + typeToCanonicalTypeName(painlessMethod.rtn) + "], " +
|
||||
typesToCanonicalTypeNames(painlessMethod.arguments) + "] " +
|
||||
"with the same arity and different return type or type parameters");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addField(String ownerStructName, WhitelistField whitelistField) {
|
||||
PainlessClassBuilder ownerStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(ownerStructName));
|
||||
public void addPainlessField(String targetCanonicalClassName, String fieldName, String typeNameParameter) {
|
||||
Objects.requireNonNull(targetCanonicalClassName);
|
||||
Objects.requireNonNull(fieldName);
|
||||
Objects.requireNonNull(typeNameParameter);
|
||||
|
||||
if (ownerStruct == null) {
|
||||
throw new IllegalArgumentException("owner struct [" + ownerStructName + "] not defined for method with " +
|
||||
"name [" + whitelistField.javaFieldName + "] and type " + whitelistField.painlessFieldTypeName);
|
||||
Class<?> targetClass = canonicalClassNamesToClasses.get(targetCanonicalClassName);
|
||||
|
||||
if (targetClass == null) {
|
||||
throw new IllegalArgumentException("class [" + targetCanonicalClassName + "] not found");
|
||||
}
|
||||
|
||||
if (FIELD_NAME_PATTERN.matcher(whitelistField.javaFieldName).matches() == false) {
|
||||
throw new IllegalArgumentException("invalid field name " +
|
||||
"[" + whitelistField.painlessFieldTypeName + "] for owner struct [" + ownerStructName + "].");
|
||||
}
|
||||
|
||||
java.lang.reflect.Field javaField;
|
||||
Class<?> typeParameter;
|
||||
|
||||
try {
|
||||
javaField = ownerStruct.clazz.getField(whitelistField.javaFieldName);
|
||||
} catch (NoSuchFieldException exception) {
|
||||
throw new IllegalArgumentException("field [" + whitelistField.javaFieldName + "] " +
|
||||
"not found for class [" + ownerStruct.clazz.getName() + "].");
|
||||
}
|
||||
|
||||
Class<?> painlessFieldClass;
|
||||
|
||||
try {
|
||||
painlessFieldClass = canonicalTypeNameToType(whitelistField.painlessFieldTypeName);
|
||||
typeParameter = canonicalTypeNameToType(typeNameParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("struct not defined for return type [" + whitelistField.painlessFieldTypeName + "] " +
|
||||
"with owner struct [" + ownerStructName + "] and field with name [" + whitelistField.javaFieldName + "]", iae);
|
||||
throw new IllegalArgumentException("type parameter [" + typeNameParameter + "] not found " +
|
||||
"for field [[" + targetCanonicalClassName + "], [" + fieldName + "]");
|
||||
}
|
||||
|
||||
|
||||
addPainlessField(targetClass, fieldName, typeParameter);
|
||||
}
|
||||
|
||||
public void addPainlessField(Class<?> targetClass, String fieldName, Class<?> typeParameter) {
|
||||
Objects.requireNonNull(targetClass);
|
||||
Objects.requireNonNull(fieldName);
|
||||
Objects.requireNonNull(typeParameter);
|
||||
|
||||
if (targetClass == def.class) {
|
||||
throw new IllegalArgumentException("cannot add field to reserved class [" + DEF_CLASS_NAME + "]");
|
||||
}
|
||||
|
||||
String targetCanonicalClassName = typeToCanonicalTypeName(targetClass);
|
||||
|
||||
if (FIELD_NAME_PATTERN.matcher(fieldName).matches() == false) {
|
||||
throw new IllegalArgumentException(
|
||||
"invalid field name [" + fieldName + "] for target class [" + targetCanonicalClassName + "].");
|
||||
}
|
||||
|
||||
|
||||
PainlessClassBuilder painlessClassBuilder = classesToPainlessClassBuilders.get(targetClass);
|
||||
|
||||
if (painlessClassBuilder == null) {
|
||||
throw new IllegalArgumentException("class [" + targetCanonicalClassName + "] not found");
|
||||
}
|
||||
|
||||
try {
|
||||
validateType(typeParameter);
|
||||
} catch (IllegalArgumentException iae) {
|
||||
throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(typeParameter) + "] not found " +
|
||||
"for field [[" + targetCanonicalClassName + "], [" + fieldName + "]", iae);
|
||||
}
|
||||
|
||||
Field javaField;
|
||||
|
||||
try {
|
||||
javaField = targetClass.getField(fieldName);
|
||||
} catch (NoSuchFieldException nsme) {
|
||||
throw new IllegalArgumentException(
|
||||
"field reflection object [[" + targetCanonicalClassName + "], [" + fieldName + "] not found", nsme);
|
||||
}
|
||||
|
||||
if (javaField.getType() != typeToJavaType(typeParameter)) {
|
||||
throw new IllegalArgumentException("type parameter [" + typeToCanonicalTypeName(javaField.getType()) + "] " +
|
||||
"does not match the specified type parameter [" + typeToCanonicalTypeName(typeParameter) + "] " +
|
||||
"for field [[" + targetCanonicalClassName + "], [" + fieldName + "]");
|
||||
}
|
||||
|
||||
String painlessFieldKey = buildPainlessFieldKey(fieldName);
|
||||
|
||||
if (Modifier.isStatic(javaField.getModifiers())) {
|
||||
if (Modifier.isFinal(javaField.getModifiers()) == false) {
|
||||
throw new IllegalArgumentException("static [" + whitelistField.javaFieldName + "] " +
|
||||
"with owner struct [" + ownerStruct.name + "] is not final");
|
||||
throw new IllegalArgumentException("static field [[" + targetCanonicalClassName + "]. [" + fieldName + "]] must be final");
|
||||
}
|
||||
|
||||
PainlessField painlessField = ownerStruct.staticMembers.get(whitelistField.javaFieldName);
|
||||
PainlessField painlessField = painlessClassBuilder.staticMembers.get(painlessFieldKey);
|
||||
|
||||
if (painlessField == null) {
|
||||
painlessField = painlessFieldCache.computeIfAbsent(
|
||||
new PainlessFieldCacheKey(ownerStruct.clazz, whitelistField.javaFieldName, painlessFieldClass),
|
||||
key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
|
||||
ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), null, null));
|
||||
ownerStruct.staticMembers.put(whitelistField.javaFieldName, painlessField);
|
||||
} else if (painlessField.clazz != painlessFieldClass) {
|
||||
throw new IllegalArgumentException("illegal duplicate static fields [" + whitelistField.javaFieldName + "] " +
|
||||
"found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");
|
||||
new PainlessFieldCacheKey(targetClass, fieldName, typeParameter),
|
||||
key -> new PainlessField(fieldName, javaField.getName(), targetClass,
|
||||
typeParameter, javaField.getModifiers(), null, null));
|
||||
|
||||
painlessClassBuilder.staticMembers.put(painlessFieldKey, painlessField);
|
||||
} else if (painlessField.clazz != typeParameter) {
|
||||
throw new IllegalArgumentException("cannot have static fields " +
|
||||
"[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
|
||||
typeToCanonicalTypeName(typeParameter) + "] and " +
|
||||
"[[" + targetCanonicalClassName + "], [" + painlessField.name + "], " +
|
||||
typeToCanonicalTypeName(painlessField.clazz) + "] " +
|
||||
"with the same and different type parameters");
|
||||
}
|
||||
} else {
|
||||
MethodHandle javaMethodHandleGetter;
|
||||
MethodHandle javaMethodHandleSetter;
|
||||
MethodHandle methodHandleGetter;
|
||||
|
||||
try {
|
||||
if (Modifier.isStatic(javaField.getModifiers()) == false) {
|
||||
javaMethodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
|
||||
javaMethodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
|
||||
} else {
|
||||
javaMethodHandleGetter = null;
|
||||
javaMethodHandleSetter = null;
|
||||
}
|
||||
} catch (IllegalAccessException exception) {
|
||||
throw new IllegalArgumentException("getter/setter [" + whitelistField.javaFieldName + "]" +
|
||||
" not found for class [" + ownerStruct.clazz.getName() + "].");
|
||||
methodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException(
|
||||
"method handle getter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
|
||||
}
|
||||
|
||||
PainlessField painlessField = ownerStruct.members.get(whitelistField.javaFieldName);
|
||||
MethodHandle methodHandleSetter;
|
||||
|
||||
try {
|
||||
methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
|
||||
} catch (IllegalAccessException iae) {
|
||||
throw new IllegalArgumentException(
|
||||
"method handle setter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
|
||||
}
|
||||
|
||||
PainlessField painlessField = painlessClassBuilder.members.get(painlessFieldKey);
|
||||
|
||||
if (painlessField == null) {
|
||||
painlessField = painlessFieldCache.computeIfAbsent(
|
||||
new PainlessFieldCacheKey(ownerStruct.clazz, whitelistField.javaFieldName, painlessFieldClass),
|
||||
key -> new PainlessField(whitelistField.javaFieldName, javaField.getName(),
|
||||
ownerStruct.clazz, painlessFieldClass, javaField.getModifiers(), javaMethodHandleGetter, javaMethodHandleSetter));
|
||||
ownerStruct.members.put(whitelistField.javaFieldName, painlessField);
|
||||
} else if (painlessField.clazz != painlessFieldClass) {
|
||||
throw new IllegalArgumentException("illegal duplicate member fields [" + whitelistField.javaFieldName + "] " +
|
||||
"found within the struct [" + ownerStruct.name + "] with type [" + whitelistField.painlessFieldTypeName + "]");
|
||||
new PainlessFieldCacheKey(targetClass, painlessFieldKey, typeParameter),
|
||||
key -> new PainlessField(fieldName, javaField.getName(), targetClass,
|
||||
typeParameter, javaField.getModifiers(), methodHandleGetter, methodHandleSetter));
|
||||
|
||||
painlessClassBuilder.members.put(fieldName, painlessField);
|
||||
} else if (painlessField.clazz != typeParameter) {
|
||||
throw new IllegalArgumentException("cannot have fields " +
|
||||
"[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
|
||||
typeToCanonicalTypeName(typeParameter) + "] and " +
|
||||
"[[" + targetCanonicalClassName + "], [" + painlessField.name + "], " +
|
||||
typeToCanonicalTypeName(painlessField.clazz) + "] " +
|
||||
"with the same and different type parameters");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void copyStruct(String struct, List<String> children) {
|
||||
final PainlessClassBuilder owner = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(struct));
|
||||
final PainlessClassBuilder owner = classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(struct));
|
||||
|
||||
if (owner == null) {
|
||||
throw new IllegalArgumentException("Owner struct [" + struct + "] not defined for copy.");
|
||||
|
@ -516,7 +675,7 @@ public class PainlessLookupBuilder {
|
|||
|
||||
for (int count = 0; count < children.size(); ++count) {
|
||||
final PainlessClassBuilder child =
|
||||
classesToPainlessClasses.get(canonicalClassNamesToClasses.get(children.get(count)));
|
||||
classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(children.get(count)));
|
||||
|
||||
if (child == null) {
|
||||
throw new IllegalArgumentException("Child struct [" + children.get(count) + "]" +
|
||||
|
@ -690,7 +849,7 @@ public class PainlessLookupBuilder {
|
|||
for (WhitelistClass whitelistStruct : whitelist.whitelistStructs) {
|
||||
String painlessTypeName = whitelistStruct.javaClassName.replace('$', '.');
|
||||
PainlessClassBuilder painlessStruct =
|
||||
classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
|
||||
classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
|
||||
|
||||
if (painlessStruct != null && painlessStruct.clazz.getName().equals(whitelistStruct.javaClassName) == false) {
|
||||
throw new IllegalArgumentException("struct [" + painlessStruct.name + "] cannot represent multiple classes " +
|
||||
|
@ -701,8 +860,8 @@ public class PainlessLookupBuilder {
|
|||
addPainlessClass(
|
||||
whitelist.javaClassLoader, whitelistStruct.javaClassName, whitelistStruct.onlyFQNJavaClassName == false);
|
||||
|
||||
painlessStruct = classesToPainlessClasses.get(canonicalClassNamesToClasses.get(painlessTypeName));
|
||||
classesToPainlessClasses.put(painlessStruct.clazz, painlessStruct);
|
||||
painlessStruct = classesToPainlessClassBuilders.get(canonicalClassNamesToClasses.get(painlessTypeName));
|
||||
classesToPainlessClassBuilders.put(painlessStruct.clazz, painlessStruct);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -715,17 +874,19 @@ public class PainlessLookupBuilder {
|
|||
|
||||
for (WhitelistConstructor whitelistConstructor : whitelistStruct.whitelistConstructors) {
|
||||
origin = whitelistConstructor.origin;
|
||||
addConstructor(painlessTypeName, whitelistConstructor);
|
||||
addPainlessConstructor(painlessTypeName, whitelistConstructor.painlessParameterTypeNames);
|
||||
}
|
||||
|
||||
for (WhitelistMethod whitelistMethod : whitelistStruct.whitelistMethods) {
|
||||
origin = whitelistMethod.origin;
|
||||
addMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod);
|
||||
addPainlessMethod(whitelist.javaClassLoader, painlessTypeName, whitelistMethod.javaAugmentedClassName,
|
||||
whitelistMethod.javaMethodName, whitelistMethod.painlessReturnTypeName,
|
||||
whitelistMethod.painlessParameterTypeNames);
|
||||
}
|
||||
|
||||
for (WhitelistField whitelistField : whitelistStruct.whitelistFields) {
|
||||
origin = whitelistField.origin;
|
||||
addField(painlessTypeName, whitelistField);
|
||||
addPainlessField(painlessTypeName, whitelistField.javaFieldName, whitelistField.painlessFieldTypeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -735,8 +896,8 @@ public class PainlessLookupBuilder {
|
|||
|
||||
// goes through each Painless struct and determines the inheritance list,
|
||||
// and then adds all inherited types to the Painless struct's whitelist
|
||||
for (Class<?> javaClass : classesToPainlessClasses.keySet()) {
|
||||
PainlessClassBuilder painlessStruct = classesToPainlessClasses.get(javaClass);
|
||||
for (Class<?> javaClass : classesToPainlessClassBuilders.keySet()) {
|
||||
PainlessClassBuilder painlessStruct = classesToPainlessClassBuilders.get(javaClass);
|
||||
|
||||
List<String> painlessSuperStructs = new ArrayList<>();
|
||||
Class<?> javaSuperClass = painlessStruct.clazz.getSuperclass();
|
||||
|
@ -747,7 +908,7 @@ public class PainlessLookupBuilder {
|
|||
// adds super classes to the inheritance list
|
||||
if (javaSuperClass != null && javaSuperClass.isInterface() == false) {
|
||||
while (javaSuperClass != null) {
|
||||
PainlessClassBuilder painlessSuperStruct = classesToPainlessClasses.get(javaSuperClass);
|
||||
PainlessClassBuilder painlessSuperStruct = classesToPainlessClassBuilders.get(javaSuperClass);
|
||||
|
||||
if (painlessSuperStruct != null) {
|
||||
painlessSuperStructs.add(painlessSuperStruct.name);
|
||||
|
@ -763,7 +924,7 @@ public class PainlessLookupBuilder {
|
|||
Class<?> javaInterfaceLookup = javaInteraceLookups.pop();
|
||||
|
||||
for (Class<?> javaSuperInterface : javaInterfaceLookup.getInterfaces()) {
|
||||
PainlessClassBuilder painlessInterfaceStruct = classesToPainlessClasses.get(javaSuperInterface);
|
||||
PainlessClassBuilder painlessInterfaceStruct = classesToPainlessClassBuilders.get(javaSuperInterface);
|
||||
|
||||
if (painlessInterfaceStruct != null) {
|
||||
String painlessInterfaceStructName = painlessInterfaceStruct.name;
|
||||
|
@ -784,7 +945,7 @@ public class PainlessLookupBuilder {
|
|||
|
||||
// copies methods and fields from Object into interface types
|
||||
if (painlessStruct.clazz.isInterface() || (def.class.getSimpleName()).equals(painlessStruct.name)) {
|
||||
PainlessClassBuilder painlessObjectStruct = classesToPainlessClasses.get(Object.class);
|
||||
PainlessClassBuilder painlessObjectStruct = classesToPainlessClassBuilders.get(Object.class);
|
||||
|
||||
if (painlessObjectStruct != null) {
|
||||
copyStruct(painlessStruct.name, Collections.singletonList(painlessObjectStruct.name));
|
||||
|
@ -793,14 +954,14 @@ public class PainlessLookupBuilder {
|
|||
}
|
||||
|
||||
// precompute runtime classes
|
||||
for (PainlessClassBuilder painlessStruct : classesToPainlessClasses.values()) {
|
||||
for (PainlessClassBuilder painlessStruct : classesToPainlessClassBuilders.values()) {
|
||||
addRuntimeClass(painlessStruct);
|
||||
}
|
||||
|
||||
Map<Class<?>, PainlessClass> javaClassesToPainlessClasses = new HashMap<>();
|
||||
|
||||
// copy all structs to make them unmodifiable for outside users:
|
||||
for (Map.Entry<Class<?>,PainlessClassBuilder> entry : classesToPainlessClasses.entrySet()) {
|
||||
for (Map.Entry<Class<?>,PainlessClassBuilder> entry : classesToPainlessClassBuilders.entrySet()) {
|
||||
entry.getValue().functionalMethod = computeFunctionalInterfaceMethod(entry.getValue());
|
||||
javaClassesToPainlessClasses.put(entry.getKey(), entry.getValue().build());
|
||||
}
|
||||
|
|
|
@ -33,10 +33,12 @@ import java.util.Objects;
|
|||
*
|
||||
* A class is a set of methods and fields under a specific class name. A type is either a class or an array under a specific type name.
|
||||
* Note the distinction between class versus type is class means that no array classes will be be represented whereas type allows array
|
||||
* classes to be represented. The set of available classes will always be a subset of the available types.
|
||||
* classes to be represented. The set of available classes will always be a subset of the available types.
|
||||
*
|
||||
* Under ambiguous circumstances most variable names are prefixed with asm, java, or painless. If the variable value is the same for asm,
|
||||
* java, and painless, no prefix is used.
|
||||
* java, and painless, no prefix is used. Target is used as a prefix to represent if a constructor, method, or field is being
|
||||
* called/accessed on that specific class. Parameter is often a postfix used to represent if a type is used as a parameter to a
|
||||
* constructor, method, or field.
|
||||
*
|
||||
* <ul>
|
||||
* <li> - javaClassName (String) - the fully qualified java class name where '$' tokens represent inner classes excluding
|
||||
|
@ -150,8 +152,8 @@ public final class PainlessLookupUtility {
|
|||
|
||||
String canonicalTypeName = type.getCanonicalName();
|
||||
|
||||
if (canonicalTypeName.startsWith(def.class.getName())) {
|
||||
canonicalTypeName = canonicalTypeName.replace(def.class.getName(), DEF_TYPE_NAME);
|
||||
if (canonicalTypeName.startsWith(def.class.getCanonicalName())) {
|
||||
canonicalTypeName = canonicalTypeName.replace(def.class.getCanonicalName(), DEF_CLASS_NAME);
|
||||
}
|
||||
|
||||
return canonicalTypeName;
|
||||
|
@ -351,7 +353,7 @@ public final class PainlessLookupUtility {
|
|||
/**
|
||||
* The def type name as specified in the source for a script.
|
||||
*/
|
||||
public static final String DEF_TYPE_NAME = "def";
|
||||
public static final String DEF_CLASS_NAME = "def";
|
||||
|
||||
/**
|
||||
* The method name for all constructors.
|
||||
|
|
|
@ -148,7 +148,7 @@ class java.lang.Character {
|
|||
int MAX_RADIX
|
||||
char MAX_SURROGATE
|
||||
char MAX_VALUE
|
||||
char MIN_CODE_POINT
|
||||
int MIN_CODE_POINT
|
||||
char MIN_HIGH_SURROGATE
|
||||
char MIN_LOW_SURROGATE
|
||||
int MIN_RADIX
|
||||
|
|
Loading…
Reference in New Issue