Painless: Clean Up PainlessClass Variables (#32380)

Removes the variables name, clazz, and type as they are unnecessary. Renames 
staticMembers -> staticFields, members -> fields, getters -> getterMethodHandles, and 
setters -> setterMethodHandles.
This commit is contained in:
Jack Conradson 2018-07-26 09:02:06 -07:00 committed by GitHub
parent 3b050194f9
commit df579f8bce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 131 additions and 142 deletions

View File

@ -19,11 +19,11 @@
package org.elasticsearch.painless.spi; package org.elasticsearch.painless.spi;
import org.elasticsearch.script.ScriptContext;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.elasticsearch.script.ScriptContext;
public interface PainlessExtension { public interface PainlessExtension {
Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists(); Map<ScriptContext<?>, List<Whitelist>> getContextWhitelists();

View File

@ -421,7 +421,7 @@ public final class Def {
PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(clazz); PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(clazz);
if (struct != null) { if (struct != null) {
MethodHandle handle = struct.getters.get(name); MethodHandle handle = struct.getterMethodHandles.get(name);
if (handle != null) { if (handle != null) {
return handle; return handle;
} }
@ -431,7 +431,7 @@ public final class Def {
struct = painlessLookup.getPainlessStructFromJavaClass(iface); struct = painlessLookup.getPainlessStructFromJavaClass(iface);
if (struct != null) { if (struct != null) {
MethodHandle handle = struct.getters.get(name); MethodHandle handle = struct.getterMethodHandles.get(name);
if (handle != null) { if (handle != null) {
return handle; return handle;
} }
@ -492,7 +492,7 @@ public final class Def {
PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(clazz); PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(clazz);
if (struct != null) { if (struct != null) {
MethodHandle handle = struct.setters.get(name); MethodHandle handle = struct.setterMethodHandles.get(name);
if (handle != null) { if (handle != null) {
return handle; return handle;
} }
@ -502,7 +502,7 @@ public final class Def {
struct = painlessLookup.getPainlessStructFromJavaClass(iface); struct = painlessLookup.getPainlessStructFromJavaClass(iface);
if (struct != null) { if (struct != null) {
MethodHandle handle = struct.setters.get(name); MethodHandle handle = struct.setterMethodHandles.get(name);
if (handle != null) { if (handle != null) {
return handle; return handle;
} }

View File

@ -22,6 +22,7 @@ package org.elasticsearch.painless;
import org.elasticsearch.painless.api.Debug; import org.elasticsearch.painless.api.Debug;
import org.elasticsearch.painless.lookup.PainlessClass; import org.elasticsearch.painless.lookup.PainlessClass;
import org.elasticsearch.painless.lookup.PainlessLookup; import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.script.ScriptException; import org.elasticsearch.script.ScriptException;
import java.util.List; import java.util.List;
@ -58,7 +59,7 @@ public class PainlessExplainError extends Error {
javaClassName = objectToExplain.getClass().getName(); javaClassName = objectToExplain.getClass().getName();
PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(objectToExplain.getClass()); PainlessClass struct = painlessLookup.getPainlessStructFromJavaClass(objectToExplain.getClass());
if (struct != null) { if (struct != null) {
painlessClassName = struct.name; painlessClassName = PainlessLookupUtility.typeToCanonicalTypeName(objectToExplain.getClass());
} }
} }

View File

@ -19,47 +19,38 @@
package org.elasticsearch.painless.lookup; package org.elasticsearch.painless.lookup;
import org.objectweb.asm.Type;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
public final class PainlessClass { public final class PainlessClass {
public final String name;
public final Class<?> clazz;
public final Type type;
public final Map<String, PainlessMethod> constructors; public final Map<String, PainlessMethod> constructors;
public final Map<String, PainlessMethod> staticMethods; public final Map<String, PainlessMethod> staticMethods;
public final Map<String, PainlessMethod> methods; public final Map<String, PainlessMethod> methods;
public final Map<String, PainlessField> staticMembers; public final Map<String, PainlessField> staticFields;
public final Map<String, PainlessField> members; public final Map<String, PainlessField> fields;
public final Map<String, MethodHandle> getters; public final Map<String, MethodHandle> getterMethodHandles;
public final Map<String, MethodHandle> setters; public final Map<String, MethodHandle> setterMethodHandles;
public final PainlessMethod functionalMethod; public final PainlessMethod functionalMethod;
PainlessClass(String name, Class<?> clazz, Type type, PainlessClass(Map<String, PainlessMethod> constructors,
Map<String, PainlessMethod> constructors, Map<String, PainlessMethod> staticMethods, Map<String, PainlessMethod> methods, Map<String, PainlessMethod> staticMethods, Map<String, PainlessMethod> methods,
Map<String, PainlessField> staticMembers, Map<String, PainlessField> members, Map<String, PainlessField> staticFields, Map<String, PainlessField> fields,
Map<String, MethodHandle> getters, Map<String, MethodHandle> setters, Map<String, MethodHandle> getterMethodHandles, Map<String, MethodHandle> setterMethodHandles,
PainlessMethod functionalMethod) { PainlessMethod functionalMethod) {
this.name = name;
this.clazz = clazz;
this.type = type;
this.constructors = Collections.unmodifiableMap(constructors); this.constructors = Collections.unmodifiableMap(constructors);
this.staticMethods = Collections.unmodifiableMap(staticMethods); this.staticMethods = Collections.unmodifiableMap(staticMethods);
this.methods = Collections.unmodifiableMap(methods); this.methods = Collections.unmodifiableMap(methods);
this.staticMembers = Collections.unmodifiableMap(staticMembers); this.staticFields = Collections.unmodifiableMap(staticFields);
this.members = Collections.unmodifiableMap(members); this.fields = Collections.unmodifiableMap(fields);
this.getters = Collections.unmodifiableMap(getters); this.getterMethodHandles = Collections.unmodifiableMap(getterMethodHandles);
this.setters = Collections.unmodifiableMap(setters); this.setterMethodHandles = Collections.unmodifiableMap(setterMethodHandles);
this.functionalMethod = functionalMethod; this.functionalMethod = functionalMethod;
} }

View File

@ -19,52 +19,39 @@
package org.elasticsearch.painless.lookup; package org.elasticsearch.painless.lookup;
import org.objectweb.asm.Type;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
final class PainlessClassBuilder { final class PainlessClassBuilder {
final String name;
final Class<?> clazz;
final Type type;
final Map<String, PainlessMethod> constructors; final Map<String, PainlessMethod> constructors;
final Map<String, PainlessMethod> staticMethods; final Map<String, PainlessMethod> staticMethods;
final Map<String, PainlessMethod> methods; final Map<String, PainlessMethod> methods;
final Map<String, PainlessField> staticMembers; final Map<String, PainlessField> staticFields;
final Map<String, PainlessField> members; final Map<String, PainlessField> fields;
final Map<String, MethodHandle> getters; final Map<String, MethodHandle> getterMethodHandles;
final Map<String, MethodHandle> setters; final Map<String, MethodHandle> setterMethodHandles;
PainlessMethod functionalMethod; PainlessMethod functionalMethod;
PainlessClassBuilder(String name, Class<?> clazz, Type type) { PainlessClassBuilder() {
this.name = name;
this.clazz = clazz;
this.type = type;
constructors = new HashMap<>(); constructors = new HashMap<>();
staticMethods = new HashMap<>(); staticMethods = new HashMap<>();
methods = new HashMap<>(); methods = new HashMap<>();
staticMembers = new HashMap<>(); staticFields = new HashMap<>();
members = new HashMap<>(); fields = new HashMap<>();
getters = new HashMap<>(); getterMethodHandles = new HashMap<>();
setters = new HashMap<>(); setterMethodHandles = new HashMap<>();
functionalMethod = null; functionalMethod = null;
} }
PainlessClass build() { PainlessClass build() {
return new PainlessClass(name, clazz, type, return new PainlessClass(constructors, staticMethods, methods, staticFields, fields,
constructors, staticMethods, methods, getterMethodHandles, setterMethodHandles, functionalMethod);
staticMembers, members,
getters, setters,
functionalMethod);
} }
} }

View File

@ -29,8 +29,8 @@ import java.util.Map;
*/ */
public final class PainlessLookup { public final class PainlessLookup {
public Collection<PainlessClass> getStructs() { public Collection<Class<?>> getStructs() {
return classesToPainlessClasses.values(); return classesToPainlessClasses.keySet();
} }
private final Map<String, Class<?>> canonicalClassNamesToClasses; private final Map<String, Class<?>> canonicalClassNamesToClasses;

View File

@ -179,8 +179,7 @@ public class PainlessLookupBuilder {
classesToPainlessClassBuilders = new HashMap<>(); classesToPainlessClassBuilders = new HashMap<>();
canonicalClassNamesToClasses.put(DEF_CLASS_NAME, def.class); canonicalClassNamesToClasses.put(DEF_CLASS_NAME, def.class);
classesToPainlessClassBuilders.put(def.class, classesToPainlessClassBuilders.put(def.class, new PainlessClassBuilder());
new PainlessClassBuilder(DEF_CLASS_NAME, Object.class, org.objectweb.asm.Type.getType(Object.class)));
} }
private Class<?> canonicalTypeNameToType(String canonicalTypeName) { private Class<?> canonicalTypeNameToType(String canonicalTypeName) {
@ -234,17 +233,21 @@ public class PainlessLookupBuilder {
throw new IllegalArgumentException("invalid class name [" + canonicalClassName + "]"); throw new IllegalArgumentException("invalid class name [" + canonicalClassName + "]");
} }
Class<?> existingClass = canonicalClassNamesToClasses.get(typeToCanonicalTypeName(clazz));
if (existingClass != null && existingClass != clazz) {
throw new IllegalArgumentException("class [" + canonicalClassName + "] " +
"cannot represent multiple java classes with the same name from different class loaders");
}
PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClassBuilders.get(clazz); PainlessClassBuilder existingPainlessClassBuilder = classesToPainlessClassBuilders.get(clazz);
if (existingPainlessClassBuilder == null) { if (existingPainlessClassBuilder == null) {
PainlessClassBuilder painlessClassBuilder = PainlessClassBuilder painlessClassBuilder = new PainlessClassBuilder();
new PainlessClassBuilder(canonicalClassName, clazz, org.objectweb.asm.Type.getType(clazz));
canonicalClassNamesToClasses.put(canonicalClassName, clazz); canonicalClassNamesToClasses.put(canonicalClassName, clazz);
classesToPainlessClassBuilders.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");
} }
String javaClassName = clazz.getName(); String javaClassName = clazz.getName();
@ -265,7 +268,7 @@ public class PainlessLookupBuilder {
canonicalClassNamesToClasses.put(importedCanonicalClassName, clazz); canonicalClassNamesToClasses.put(importedCanonicalClassName, clazz);
} }
} else if (importedPainlessClass.equals(clazz) == false) { } else if (importedPainlessClass != clazz) {
throw new IllegalArgumentException("imported class [" + importedCanonicalClassName + "] cannot represent multiple " + throw new IllegalArgumentException("imported class [" + importedCanonicalClassName + "] cannot represent multiple " +
"classes [" + canonicalClassName + "] and [" + typeToCanonicalTypeName(importedPainlessClass) + "]"); "classes [" + canonicalClassName + "] and [" + typeToCanonicalTypeName(importedPainlessClass) + "]");
} else if (importClassName == false) { } else if (importClassName == false) {
@ -504,10 +507,10 @@ public class PainlessLookupBuilder {
if (painlessMethod == null) { if (painlessMethod == null) {
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
MethodHandle javaMethodHandle; MethodHandle methodHandle;
try { try {
javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod); methodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
} catch (IllegalAccessException iae) { } catch (IllegalAccessException iae) {
throw new IllegalArgumentException("static method handle [[" + targetClass.getCanonicalName() + "], " + throw new IllegalArgumentException("static method handle [[" + targetClass.getCanonicalName() + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae); "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
@ -516,7 +519,7 @@ public class PainlessLookupBuilder {
painlessMethod = painlessMethodCache.computeIfAbsent( painlessMethod = painlessMethodCache.computeIfAbsent(
new PainlessMethodCacheKey(targetClass, methodName, typeParameters), new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
key -> new PainlessMethod(methodName, targetClass, null, returnType, key -> new PainlessMethod(methodName, targetClass, null, returnType,
typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle));
painlessClassBuilder.staticMethods.put(painlessMethodKey, painlessMethod); painlessClassBuilder.staticMethods.put(painlessMethodKey, painlessMethod);
} else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType && } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
@ -535,18 +538,18 @@ public class PainlessLookupBuilder {
if (painlessMethod == null) { if (painlessMethod == null) {
org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod); org.objectweb.asm.commons.Method asmMethod = org.objectweb.asm.commons.Method.getMethod(javaMethod);
MethodHandle javaMethodHandle; MethodHandle methodHandle;
if (augmentedClass == null) { if (augmentedClass == null) {
try { try {
javaMethodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod); methodHandle = MethodHandles.publicLookup().in(targetClass).unreflect(javaMethod);
} catch (IllegalAccessException iae) { } catch (IllegalAccessException iae) {
throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " + throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae); "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found", iae);
} }
} else { } else {
try { try {
javaMethodHandle = MethodHandles.publicLookup().in(augmentedClass).unreflect(javaMethod); methodHandle = MethodHandles.publicLookup().in(augmentedClass).unreflect(javaMethod);
} catch (IllegalAccessException iae) { } catch (IllegalAccessException iae) {
throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " + throw new IllegalArgumentException("method handle [[" + targetClass.getCanonicalName() + "], " +
"[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " + "[" + methodName + "], " + typesToCanonicalTypeNames(typeParameters) + "] not found " +
@ -557,7 +560,7 @@ public class PainlessLookupBuilder {
painlessMethod = painlessMethodCache.computeIfAbsent( painlessMethod = painlessMethodCache.computeIfAbsent(
new PainlessMethodCacheKey(targetClass, methodName, typeParameters), new PainlessMethodCacheKey(targetClass, methodName, typeParameters),
key -> new PainlessMethod(methodName, targetClass, augmentedClass, returnType, key -> new PainlessMethod(methodName, targetClass, augmentedClass, returnType,
typeParameters, asmMethod, javaMethod.getModifiers(), javaMethodHandle)); typeParameters, asmMethod, javaMethod.getModifiers(), methodHandle));
painlessClassBuilder.methods.put(painlessMethodKey, painlessMethod); painlessClassBuilder.methods.put(painlessMethodKey, painlessMethod);
} else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType && } else if ((painlessMethod.name.equals(methodName) && painlessMethod.rtn == returnType &&
@ -650,7 +653,7 @@ public class PainlessLookupBuilder {
throw new IllegalArgumentException("static field [[" + targetCanonicalClassName + "]. [" + fieldName + "]] must be final"); throw new IllegalArgumentException("static field [[" + targetCanonicalClassName + "]. [" + fieldName + "]] must be final");
} }
PainlessField painlessField = painlessClassBuilder.staticMembers.get(painlessFieldKey); PainlessField painlessField = painlessClassBuilder.staticFields.get(painlessFieldKey);
if (painlessField == null) { if (painlessField == null) {
painlessField = painlessFieldCache.computeIfAbsent( painlessField = painlessFieldCache.computeIfAbsent(
@ -658,7 +661,7 @@ public class PainlessLookupBuilder {
key -> new PainlessField(fieldName, javaField.getName(), targetClass, key -> new PainlessField(fieldName, javaField.getName(), targetClass,
typeParameter, javaField.getModifiers(), null, null)); typeParameter, javaField.getModifiers(), null, null));
painlessClassBuilder.staticMembers.put(painlessFieldKey, painlessField); painlessClassBuilder.staticFields.put(painlessFieldKey, painlessField);
} else if (painlessField.clazz != typeParameter) { } else if (painlessField.clazz != typeParameter) {
throw new IllegalArgumentException("cannot have static fields " + throw new IllegalArgumentException("cannot have static fields " +
"[[" + targetCanonicalClassName + "], [" + fieldName + "], [" + "[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
@ -674,7 +677,7 @@ public class PainlessLookupBuilder {
methodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField); methodHandleGetter = MethodHandles.publicLookup().unreflectGetter(javaField);
} catch (IllegalAccessException iae) { } catch (IllegalAccessException iae) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"method handle getter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]"); "getter method handle not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
} }
MethodHandle methodHandleSetter; MethodHandle methodHandleSetter;
@ -683,10 +686,10 @@ public class PainlessLookupBuilder {
methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField); methodHandleSetter = MethodHandles.publicLookup().unreflectSetter(javaField);
} catch (IllegalAccessException iae) { } catch (IllegalAccessException iae) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"method handle setter not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]"); "setter method handle not found for field [[" + targetCanonicalClassName + "], [" + fieldName + "]]");
} }
PainlessField painlessField = painlessClassBuilder.members.get(painlessFieldKey); PainlessField painlessField = painlessClassBuilder.fields.get(painlessFieldKey);
if (painlessField == null) { if (painlessField == null) {
painlessField = painlessFieldCache.computeIfAbsent( painlessField = painlessFieldCache.computeIfAbsent(
@ -694,7 +697,7 @@ public class PainlessLookupBuilder {
key -> new PainlessField(fieldName, javaField.getName(), targetClass, key -> new PainlessField(fieldName, javaField.getName(), targetClass,
typeParameter, javaField.getModifiers(), methodHandleGetter, methodHandleSetter)); typeParameter, javaField.getModifiers(), methodHandleGetter, methodHandleSetter));
painlessClassBuilder.members.put(fieldName, painlessField); painlessClassBuilder.fields.put(fieldName, painlessField);
} else if (painlessField.clazz != typeParameter) { } else if (painlessField.clazz != typeParameter) {
throw new IllegalArgumentException("cannot have fields " + throw new IllegalArgumentException("cannot have fields " +
"[[" + targetCanonicalClassName + "], [" + fieldName + "], [" + "[[" + targetCanonicalClassName + "], [" + fieldName + "], [" +
@ -771,14 +774,14 @@ public class PainlessLookupBuilder {
} }
} }
for (Map.Entry<String, PainlessField> painlessFieldEntry : originalPainlessClassBuilder.members.entrySet()) { for (Map.Entry<String, PainlessField> painlessFieldEntry : originalPainlessClassBuilder.fields.entrySet()) {
String painlessFieldKey = painlessFieldEntry.getKey(); String painlessFieldKey = painlessFieldEntry.getKey();
PainlessField newPainlessField = painlessFieldEntry.getValue(); PainlessField newPainlessField = painlessFieldEntry.getValue();
PainlessField existingPainlessField = targetPainlessClassBuilder.members.get(painlessFieldKey); PainlessField existingPainlessField = targetPainlessClassBuilder.fields.get(painlessFieldKey);
if (existingPainlessField == null || existingPainlessField.target != newPainlessField.target && if (existingPainlessField == null || existingPainlessField.target != newPainlessField.target &&
existingPainlessField.target.isAssignableFrom(newPainlessField.target)) { existingPainlessField.target.isAssignableFrom(newPainlessField.target)) {
targetPainlessClassBuilder.members.put(painlessFieldKey, newPainlessField); targetPainlessClassBuilder.fields.put(painlessFieldKey, newPainlessField);
} }
} }
} }
@ -796,34 +799,32 @@ public class PainlessLookupBuilder {
if (typeParametersSize == 0 && methodName.startsWith("get") && methodName.length() > 3 && if (typeParametersSize == 0 && methodName.startsWith("get") && methodName.length() > 3 &&
Character.isUpperCase(methodName.charAt(3))) { Character.isUpperCase(methodName.charAt(3))) {
painlessClassBuilder.getters.putIfAbsent( painlessClassBuilder.getterMethodHandles.putIfAbsent(
Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle); Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle);
} else if (typeParametersSize == 0 && methodName.startsWith("is") && methodName.length() > 2 && } else if (typeParametersSize == 0 && methodName.startsWith("is") && methodName.length() > 2 &&
Character.isUpperCase(methodName.charAt(2))) { Character.isUpperCase(methodName.charAt(2))) {
painlessClassBuilder.getters.putIfAbsent( painlessClassBuilder.getterMethodHandles.putIfAbsent(
Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3), painlessMethod.handle); Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3), painlessMethod.handle);
} else if (typeParametersSize == 1 && methodName.startsWith("set") && methodName.length() > 3 && } else if (typeParametersSize == 1 && methodName.startsWith("set") && methodName.length() > 3 &&
Character.isUpperCase(methodName.charAt(3))) { Character.isUpperCase(methodName.charAt(3))) {
painlessClassBuilder.setters.putIfAbsent( painlessClassBuilder.setterMethodHandles.putIfAbsent(
Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle); Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4), painlessMethod.handle);
} }
} }
for (PainlessField painlessField : painlessClassBuilder.members.values()) { for (PainlessField painlessField : painlessClassBuilder.fields.values()) {
painlessClassBuilder.getters.put(painlessField.name, painlessField.getter); painlessClassBuilder.getterMethodHandles.put(painlessField.name, painlessField.getter);
painlessClassBuilder.setters.put(painlessField.name, painlessField.setter); painlessClassBuilder.setterMethodHandles.put(painlessField.name, painlessField.setter);
} }
} }
private void setFunctionalInterfaceMethods() { private void setFunctionalInterfaceMethods() {
for (Map.Entry<Class<?>, PainlessClassBuilder> painlessClassBuilderEntry : classesToPainlessClassBuilders.entrySet()) { for (Map.Entry<Class<?>, PainlessClassBuilder> painlessClassBuilderEntry : classesToPainlessClassBuilders.entrySet()) {
setFunctionalInterfaceMethod(painlessClassBuilderEntry.getValue()); setFunctionalInterfaceMethod(painlessClassBuilderEntry.getKey(), painlessClassBuilderEntry.getValue());
} }
} }
private void setFunctionalInterfaceMethod(PainlessClassBuilder painlessClassBuilder) { private void setFunctionalInterfaceMethod(Class<?> targetClass, PainlessClassBuilder painlessClassBuilder) {
Class<?> targetClass = painlessClassBuilder.clazz;
if (targetClass.isInterface()) { if (targetClass.isInterface()) {
List<java.lang.reflect.Method> javaMethods = new ArrayList<>(); List<java.lang.reflect.Method> javaMethods = new ArrayList<>();

View File

@ -72,8 +72,9 @@ public final class ENewObj extends AExpression {
constructor.arguments.toArray(types); constructor.arguments.toArray(types);
if (constructor.arguments.size() != arguments.size()) { if (constructor.arguments.size() != arguments.size()) {
throw createError(new IllegalArgumentException("When calling constructor on type [" + struct.name + "]" + throw createError(new IllegalArgumentException(
" expected [" + constructor.arguments.size() + "] arguments, but found [" + arguments.size() + "].")); "When calling constructor on type [" + PainlessLookupUtility.typeToCanonicalTypeName(actual) + "] " +
"expected [" + constructor.arguments.size() + "] arguments, but found [" + arguments.size() + "]."));
} }
for (int argument = 0; argument < arguments.size(); ++argument) { for (int argument = 0; argument < arguments.size(); ++argument) {
@ -87,7 +88,8 @@ public final class ENewObj extends AExpression {
statement = true; statement = true;
} else { } else {
throw createError(new IllegalArgumentException("Unknown new call on type [" + struct.name + "].")); throw createError(new IllegalArgumentException(
"Unknown new call on type [" + PainlessLookupUtility.typeToCanonicalTypeName(actual) + "]."));
} }
} }

View File

@ -63,9 +63,9 @@ public final class PBrace extends AStoreable {
} else if (prefix.actual == def.class) { } else if (prefix.actual == def.class) {
sub = new PSubDefArray(location, index); sub = new PSubDefArray(location, index);
} else if (Map.class.isAssignableFrom(prefix.actual)) { } else if (Map.class.isAssignableFrom(prefix.actual)) {
sub = new PSubMapShortcut(location, locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual), index); sub = new PSubMapShortcut(location, prefix.actual, index);
} else if (List.class.isAssignableFrom(prefix.actual)) { } else if (List.class.isAssignableFrom(prefix.actual)) {
sub = new PSubListShortcut(location, locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual), index); sub = new PSubListShortcut(location, prefix.actual, index);
} else { } else {
throw createError(new IllegalArgumentException("Illegal array access on type " + throw createError(new IllegalArgumentException("Illegal array access on type " +
"[" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "].")); "[" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "]."));

View File

@ -84,8 +84,8 @@ public final class PCallInvoke extends AExpression {
} else if (prefix.actual == def.class) { } else if (prefix.actual == def.class) {
sub = new PSubDefCall(location, name, arguments); sub = new PSubDefCall(location, name, arguments);
} else { } else {
throw createError(new IllegalArgumentException( throw createError(new IllegalArgumentException("Unknown call [" + name + "] with [" + arguments.size() + "] arguments " +
"Unknown call [" + name + "] with [" + arguments.size() + "] arguments on type [" + struct.name + "].")); "on type [" + PainlessLookupUtility.typeToCanonicalTypeName(prefix.actual) + "]."));
} }
if (nullSafe) { if (nullSafe) {

View File

@ -68,7 +68,7 @@ public final class PField extends AStoreable {
sub = new PSubDefField(location, value); sub = new PSubDefField(location, value);
} else { } else {
PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual); PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(prefix.actual);
PainlessField field = prefix instanceof EStatic ? struct.staticMembers.get(value) : struct.members.get(value); PainlessField field = prefix instanceof EStatic ? struct.staticFields.get(value) : struct.fields.get(value);
if (field != null) { if (field != null) {
sub = new PSubField(location, field); sub = new PSubField(location, field);
@ -92,11 +92,11 @@ public final class PField extends AStoreable {
index.analyze(locals); index.analyze(locals);
if (Map.class.isAssignableFrom(prefix.actual)) { if (Map.class.isAssignableFrom(prefix.actual)) {
sub = new PSubMapShortcut(location, struct, index); sub = new PSubMapShortcut(location, prefix.actual, index);
} }
if (List.class.isAssignableFrom(prefix.actual)) { if (List.class.isAssignableFrom(prefix.actual)) {
sub = new PSubListShortcut(location, struct, index); sub = new PSubListShortcut(location, prefix.actual, index);
} }
} }
} }

View File

@ -36,16 +36,16 @@ import java.util.Set;
*/ */
final class PSubListShortcut extends AStoreable { final class PSubListShortcut extends AStoreable {
private final PainlessClass struct; private final Class<?> targetClass;
private AExpression index; private AExpression index;
private PainlessMethod getter; private PainlessMethod getter;
private PainlessMethod setter; private PainlessMethod setter;
PSubListShortcut(Location location, PainlessClass struct, AExpression index) { PSubListShortcut(Location location, Class<?> targetClass, AExpression index) {
super(location); super(location);
this.struct = Objects.requireNonNull(struct); this.targetClass = Objects.requireNonNull(targetClass);
this.index = Objects.requireNonNull(index); this.index = Objects.requireNonNull(index);
} }
@ -56,16 +56,19 @@ final class PSubListShortcut extends AStoreable {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(targetClass);
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass);
getter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("get", 1)); getter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("get", 1));
setter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("set", 2)); setter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("set", 2));
if (getter != null && (getter.rtn == void.class || getter.arguments.size() != 1 || if (getter != null && (getter.rtn == void.class || getter.arguments.size() != 1 ||
getter.arguments.get(0) != int.class)) { getter.arguments.get(0) != int.class)) {
throw createError(new IllegalArgumentException("Illegal list get shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal list get shortcut for type [" + canonicalClassName + "]."));
} }
if (setter != null && (setter.arguments.size() != 2 || setter.arguments.get(0) != int.class)) { if (setter != null && (setter.arguments.size() != 2 || setter.arguments.get(0) != int.class)) {
throw createError(new IllegalArgumentException("Illegal list set shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal list set shortcut for type [" + canonicalClassName + "]."));
} }
if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0)) if (getter != null && setter != null && (!getter.arguments.get(0).equals(setter.arguments.get(0))
@ -80,7 +83,7 @@ final class PSubListShortcut extends AStoreable {
actual = setter != null ? setter.arguments.get(1) : getter.rtn; actual = setter != null ? setter.arguments.get(1) : getter.rtn;
} else { } else {
throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal list shortcut for type [" + canonicalClassName + "]."));
} }
} }

View File

@ -35,16 +35,16 @@ import java.util.Set;
*/ */
final class PSubMapShortcut extends AStoreable { final class PSubMapShortcut extends AStoreable {
private final PainlessClass struct; private final Class<?> targetClass;
private AExpression index; private AExpression index;
private PainlessMethod getter; private PainlessMethod getter;
private PainlessMethod setter; private PainlessMethod setter;
PSubMapShortcut(Location location, PainlessClass struct, AExpression index) { PSubMapShortcut(Location location, Class<?> targetClass, AExpression index) {
super(location); super(location);
this.struct = Objects.requireNonNull(struct); this.targetClass = Objects.requireNonNull(targetClass);
this.index = Objects.requireNonNull(index); this.index = Objects.requireNonNull(index);
} }
@ -55,15 +55,18 @@ final class PSubMapShortcut extends AStoreable {
@Override @Override
void analyze(Locals locals) { void analyze(Locals locals) {
PainlessClass struct = locals.getPainlessLookup().getPainlessStructFromJavaClass(targetClass);
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(targetClass);
getter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("get", 1)); getter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("get", 1));
setter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("put", 2)); setter = struct.methods.get(PainlessLookupUtility.buildPainlessMethodKey("put", 2));
if (getter != null && (getter.rtn == void.class || getter.arguments.size() != 1)) { if (getter != null && (getter.rtn == void.class || getter.arguments.size() != 1)) {
throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal map get shortcut for type [" + canonicalClassName + "]."));
} }
if (setter != null && setter.arguments.size() != 2) { if (setter != null && setter.arguments.size() != 2) {
throw createError(new IllegalArgumentException("Illegal map set shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal map set shortcut for type [" + canonicalClassName + "]."));
} }
if (getter != null && setter != null && if (getter != null && setter != null &&
@ -78,7 +81,7 @@ final class PSubMapShortcut extends AStoreable {
actual = setter != null ? setter.arguments.get(1) : getter.rtn; actual = setter != null ? setter.arguments.get(1) : getter.rtn;
} else { } else {
throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + struct.name + "].")); throw createError(new IllegalArgumentException("Illegal map shortcut for type [" + canonicalClassName + "]."));
} }
} }

View File

@ -29,6 +29,7 @@ import org.elasticsearch.painless.lookup.PainlessLookup;
import org.elasticsearch.painless.lookup.PainlessLookupBuilder; import org.elasticsearch.painless.lookup.PainlessLookupBuilder;
import org.elasticsearch.painless.lookup.PainlessLookupUtility; import org.elasticsearch.painless.lookup.PainlessLookupUtility;
import org.elasticsearch.painless.lookup.PainlessMethod; import org.elasticsearch.painless.lookup.PainlessMethod;
import org.elasticsearch.painless.lookup.def;
import org.elasticsearch.painless.spi.Whitelist; import org.elasticsearch.painless.spi.Whitelist;
import java.io.IOException; import java.io.IOException;
@ -71,52 +72,54 @@ public class PainlessDocGenerator {
Files.newOutputStream(indexPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE), Files.newOutputStream(indexPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE),
false, StandardCharsets.UTF_8.name())) { false, StandardCharsets.UTF_8.name())) {
emitGeneratedWarning(indexStream); emitGeneratedWarning(indexStream);
List<PainlessClass> structs = PAINLESS_LOOKUP.getStructs().stream().sorted(comparing(t -> t.name)).collect(toList()); List<Class<?>> classes = PAINLESS_LOOKUP.getStructs().stream().sorted(comparing(Class::getCanonicalName)).collect(toList());
for (PainlessClass struct : structs) { for (Class<?> clazz : classes) {
if (struct.clazz.isPrimitive()) { PainlessClass struct = PAINLESS_LOOKUP.getPainlessStructFromJavaClass(clazz);
String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(clazz);
if (clazz.isPrimitive()) {
// Primitives don't have methods to reference // Primitives don't have methods to reference
continue; continue;
} }
if ("def".equals(struct.name)) { if (clazz == def.class) {
// def is special but doesn't have any methods all of its own. // def is special but doesn't have any methods all of its own.
continue; continue;
} }
indexStream.print("include::"); indexStream.print("include::");
indexStream.print(struct.name); indexStream.print(canonicalClassName);
indexStream.println(".asciidoc[]"); indexStream.println(".asciidoc[]");
Path typePath = apiRootPath.resolve(struct.name + ".asciidoc"); Path typePath = apiRootPath.resolve(canonicalClassName + ".asciidoc");
logger.info("Writing [{}.asciidoc]", struct.name); logger.info("Writing [{}.asciidoc]", canonicalClassName);
try (PrintStream typeStream = new PrintStream( try (PrintStream typeStream = new PrintStream(
Files.newOutputStream(typePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE), Files.newOutputStream(typePath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE),
false, StandardCharsets.UTF_8.name())) { false, StandardCharsets.UTF_8.name())) {
emitGeneratedWarning(typeStream); emitGeneratedWarning(typeStream);
typeStream.print("[["); typeStream.print("[[");
emitAnchor(typeStream, struct.clazz); emitAnchor(typeStream, clazz);
typeStream.print("]]++"); typeStream.print("]]++");
typeStream.print(struct.name); typeStream.print(canonicalClassName);
typeStream.println("++::"); typeStream.println("++::");
Consumer<PainlessField> documentField = field -> PainlessDocGenerator.documentField(typeStream, field); Consumer<PainlessField> documentField = field -> PainlessDocGenerator.documentField(typeStream, field);
Consumer<PainlessMethod> documentMethod = method -> PainlessDocGenerator.documentMethod(typeStream, method); Consumer<PainlessMethod> documentMethod = method -> PainlessDocGenerator.documentMethod(typeStream, method);
struct.staticMembers.values().stream().sorted(FIELD_NAME).forEach(documentField); struct.staticFields.values().stream().sorted(FIELD_NAME).forEach(documentField);
struct.members.values().stream().sorted(FIELD_NAME).forEach(documentField); struct.fields.values().stream().sorted(FIELD_NAME).forEach(documentField);
struct.staticMethods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(documentMethod); struct.staticMethods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(documentMethod);
struct.constructors.values().stream().sorted(NUMBER_OF_ARGS).forEach(documentMethod); struct.constructors.values().stream().sorted(NUMBER_OF_ARGS).forEach(documentMethod);
Map<String, PainlessClass> inherited = new TreeMap<>(); Map<String, Class<?>> inherited = new TreeMap<>();
struct.methods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(method -> { struct.methods.values().stream().sorted(METHOD_NAME.thenComparing(NUMBER_OF_ARGS)).forEach(method -> {
if (method.target == struct.clazz) { if (method.target == clazz) {
documentMethod(typeStream, method); documentMethod(typeStream, method);
} else { } else {
PainlessClass painlessClass = PAINLESS_LOOKUP.getPainlessStructFromJavaClass(method.target); inherited.put(canonicalClassName, method.target);
inherited.put(painlessClass.name, painlessClass);
} }
}); });
if (false == inherited.isEmpty()) { if (false == inherited.isEmpty()) {
typeStream.print("* Inherits methods from "); typeStream.print("* Inherits methods from ");
boolean first = true; boolean first = true;
for (PainlessClass inheritsFrom : inherited.values()) { for (Class<?> inheritsFrom : inherited.values()) {
if (first) { if (first) {
first = false; first = false;
} else { } else {
@ -242,7 +245,7 @@ public class PainlessDocGenerator {
an internal link with the text. an internal link with the text.
*/ */
private static void emitType(PrintStream stream, Class<?> clazz) { private static void emitType(PrintStream stream, Class<?> clazz) {
emitStruct(stream, PAINLESS_LOOKUP.getPainlessStructFromJavaClass(clazz)); emitStruct(stream, clazz);
while ((clazz = clazz.getComponentType()) != null) { while ((clazz = clazz.getComponentType()) != null) {
stream.print("[]"); stream.print("[]");
} }
@ -252,15 +255,17 @@ public class PainlessDocGenerator {
* Emit a {@link PainlessClass}. If the {@linkplain PainlessClass} is primitive or def this just emits the name of the struct. * Emit a {@link PainlessClass}. If the {@linkplain PainlessClass} is primitive or def this just emits the name of the struct.
* Otherwise this emits an internal link with the name. * Otherwise this emits an internal link with the name.
*/ */
private static void emitStruct(PrintStream stream, PainlessClass struct) { private static void emitStruct(PrintStream stream, Class<?> clazz) {
if (false == struct.clazz.isPrimitive() && false == struct.name.equals("def")) { String canonicalClassName = PainlessLookupUtility.typeToCanonicalTypeName(clazz);
if (false == clazz.isPrimitive() && clazz != def.class) {
stream.print("<<"); stream.print("<<");
emitAnchor(stream, struct.clazz); emitAnchor(stream, clazz);
stream.print(','); stream.print(',');
stream.print(struct.name); stream.print(canonicalClassName);
stream.print(">>"); stream.print(">>");
} else { } else {
stream.print(struct.name); stream.print(canonicalClassName);
} }
} }

View File

@ -460,7 +460,7 @@ public class NodeToStringTests extends ESTestCase {
public void testPSubField() { public void testPSubField() {
Location l = new Location(getTestName(), 0); Location l = new Location(getTestName(), 0);
PainlessClass s = painlessLookup.getPainlessStructFromJavaClass(Boolean.class); PainlessClass s = painlessLookup.getPainlessStructFromJavaClass(Boolean.class);
PainlessField f = s.staticMembers.get("TRUE"); PainlessField f = s.staticFields.get("TRUE");
PSubField node = new PSubField(l, f); PSubField node = new PSubField(l, f);
node.prefix = new EStatic(l, "Boolean"); node.prefix = new EStatic(l, "Boolean");
assertEquals("(PSubField (EStatic Boolean) TRUE)", node.toString()); assertEquals("(PSubField (EStatic Boolean) TRUE)", node.toString());
@ -469,32 +469,28 @@ public class NodeToStringTests extends ESTestCase {
public void testPSubListShortcut() { public void testPSubListShortcut() {
Location l = new Location(getTestName(), 0); Location l = new Location(getTestName(), 0);
PainlessClass s = painlessLookup.getPainlessStructFromJavaClass(List.class); PSubListShortcut node = new PSubListShortcut(l, List.class, new EConstant(l, 1));
PSubListShortcut node = new PSubListShortcut(l, s, new EConstant(l, 1));
node.prefix = new EVariable(l, "a"); node.prefix = new EVariable(l, "a");
assertEquals("(PSubListShortcut (EVariable a) (EConstant Integer 1))", node.toString()); assertEquals("(PSubListShortcut (EVariable a) (EConstant Integer 1))", node.toString());
assertEquals("(PSubNullSafeCallInvoke (PSubListShortcut (EVariable a) (EConstant Integer 1)))", assertEquals("(PSubNullSafeCallInvoke (PSubListShortcut (EVariable a) (EConstant Integer 1)))",
new PSubNullSafeCallInvoke(l, node).toString()); new PSubNullSafeCallInvoke(l, node).toString());
l = new Location(getTestName(), 0); l = new Location(getTestName(), 0);
s = painlessLookup.getPainlessStructFromJavaClass(List.class); node = new PSubListShortcut(l, List.class, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4)));
node = new PSubListShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4)));
node.prefix = new EVariable(l, "a"); node.prefix = new EVariable(l, "a");
assertEquals("(PSubListShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); assertEquals("(PSubListShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString());
} }
public void testPSubMapShortcut() { public void testPSubMapShortcut() {
Location l = new Location(getTestName(), 0); Location l = new Location(getTestName(), 0);
PainlessClass s = painlessLookup.getPainlessStructFromJavaClass(Map.class); PSubMapShortcut node = new PSubMapShortcut(l, Map.class, new EConstant(l, "cat"));
PSubMapShortcut node = new PSubMapShortcut(l, s, new EConstant(l, "cat"));
node.prefix = new EVariable(l, "a"); node.prefix = new EVariable(l, "a");
assertEquals("(PSubMapShortcut (EVariable a) (EConstant String 'cat'))", node.toString()); assertEquals("(PSubMapShortcut (EVariable a) (EConstant String 'cat'))", node.toString());
assertEquals("(PSubNullSafeCallInvoke (PSubMapShortcut (EVariable a) (EConstant String 'cat')))", assertEquals("(PSubNullSafeCallInvoke (PSubMapShortcut (EVariable a) (EConstant String 'cat')))",
new PSubNullSafeCallInvoke(l, node).toString()); new PSubNullSafeCallInvoke(l, node).toString());
l = new Location(getTestName(), 1); l = new Location(getTestName(), 1);
s = painlessLookup.getPainlessStructFromJavaClass(Map.class); node = new PSubMapShortcut(l, Map.class, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4)));
node = new PSubMapShortcut(l, s, new EBinary(l, Operation.ADD, new EConstant(l, 1), new EConstant(l, 4)));
node.prefix = new EVariable(l, "a"); node.prefix = new EVariable(l, "a");
assertEquals("(PSubMapShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString()); assertEquals("(PSubMapShortcut (EVariable a) (EBinary (EConstant Integer 1) + (EConstant Integer 4)))", node.toString());
} }