Painless: Modify Loader to Load Classes Directly from Definition (#28088)

This commit is contained in:
Jack Conradson 2018-01-05 13:06:36 -08:00 committed by GitHub
parent 27bbec0c19
commit b5377d294f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 144 additions and 89 deletions

View File

@ -69,12 +69,28 @@ final class Compiler {
*/
static final class Loader extends SecureClassLoader {
private final AtomicInteger lambdaCounter = new AtomicInteger(0);
private final Definition definition;
/**
* @param parent The parent ClassLoader.
*/
Loader(ClassLoader parent) {
Loader(ClassLoader parent, Definition definition) {
super(parent);
this.definition = definition;
}
/**
* Will check to see if the {@link Class} has already been loaded when
* the {@link Definition} was initially created. Allows for {@link Whitelist}ed
* classes to be loaded from other modules/plugins without a direct relationship
* to the module's/plugin's {@link ClassLoader}.
*/
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
Class<?> found = definition.getClassFromBinaryName(name);
return found != null ? found : super.findClass(name);
}
/**
@ -116,6 +132,14 @@ final class Compiler {
}
}
/**
* Return a new {@link Loader} for a script using the
* {@link Compiler}'s specified {@link Definition}.
*/
public Loader createLoader(ClassLoader parent) {
return new Loader(parent, definition);
}
/**
* The class/interface the script is guaranteed to derive/implement.
*/

View File

@ -43,7 +43,7 @@ public final class Definition {
private static final Pattern TYPE_NAME_PATTERN = Pattern.compile("^[_a-zA-Z][._a-zA-Z0-9]*$");
private static final String[] DEFINITION_FILES = new String[] {
public static final String[] DEFINITION_FILES = new String[] {
"org.elasticsearch.txt",
"java.lang.txt",
"java.math.txt",
@ -522,6 +522,12 @@ public final class Definition {
return runtimeMap.get(clazz);
}
public Class<?> getClassFromBinaryName(String name) {
Struct struct = structsMap.get(name.replace('$', '.'));
return struct == null ? null : struct.clazz;
}
/** Collection of all simple types. Used by {@code PainlessDocGenerator} to generate an API reference. */
Collection<Type> allSimpleTypes() {
return simpleTypesMap.values();
@ -535,7 +541,7 @@ public final class Definition {
public AnalyzerCaster caster;
private Definition(List<Whitelist> whitelists) {
public Definition(List<Whitelist> whitelists) {
structsMap = new HashMap<>();
simpleTypesMap = new HashMap<>();
runtimeMap = new HashMap<>();

View File

@ -37,11 +37,6 @@ import java.util.List;
*/
public final class PainlessPlugin extends Plugin implements ScriptPlugin, ExtensiblePlugin {
// force to parse our definition at startup (not on the user's first script)
static {
Definition.DEFINITION.hashCode();
}
@Override
public ScriptEngine getScriptEngine(Settings settings, Collection<ScriptContext<?>> contexts) {
return new PainlessScriptEngine(settings, contexts);

View File

@ -99,11 +99,16 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr
Map<ScriptContext<?>, Compiler> contextsToCompilers = new HashMap<>();
// Placeholder definition used for all contexts until SPI is fully integrated. Reduces memory foot print
// by re-using the same definition since caching isn't implemented at this time.
Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
for (ScriptContext<?> context : contexts) {
if (context.instanceClazz.equals(SearchScript.class) || context.instanceClazz.equals(ExecutableScript.class)) {
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, Definition.DEFINITION));
contextsToCompilers.put(context, new Compiler(GenericElasticsearchScript.class, definition));
} else {
contextsToCompilers.put(context, new Compiler(context.instanceClazz, Definition.DEFINITION));
contextsToCompilers.put(context, new Compiler(context.instanceClazz, definition));
}
}
@ -126,9 +131,11 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr
@Override
public <T> T compile(String scriptName, String scriptSource, ScriptContext<T> context, Map<String, String> params) {
Compiler compiler = contextsToCompilers.get(context);
if (context.instanceClazz.equals(SearchScript.class)) {
GenericElasticsearchScript painlessScript =
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);
SearchScript.Factory factory = (p, lookup) -> new SearchScript.LeafFactory() {
@Override
@ -143,7 +150,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr
return context.factoryClazz.cast(factory);
} else if (context.instanceClazz.equals(ExecutableScript.class)) {
GenericElasticsearchScript painlessScript =
(GenericElasticsearchScript)compile(contextsToCompilers.get(context), scriptName, scriptSource, params);
(GenericElasticsearchScript)compile(compiler, scriptName, scriptSource, params);
ExecutableScript.Factory factory = (p) -> new ScriptImpl(painlessScript, p, null, null);
return context.factoryClazz.cast(factory);
@ -155,7 +162,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
@Override
public Loader run() {
return new Loader(getClass().getClassLoader());
return compiler.createLoader(getClass().getClassLoader());
}
});
@ -414,7 +421,7 @@ public final class PainlessScriptEngine extends AbstractComponent implements Scr
final Loader loader = AccessController.doPrivileged(new PrivilegedAction<Loader>() {
@Override
public Loader run() {
return new Loader(getClass().getClassLoader());
return compiler.createLoader(getClass().getClassLoader());
}
});

View File

@ -23,75 +23,82 @@ import org.elasticsearch.painless.Definition.Cast;
import org.elasticsearch.painless.Definition.Type;
import org.elasticsearch.test.ESTestCase;
import java.util.Collections;
import static org.elasticsearch.painless.Definition.DEFINITION_FILES;
public class AnalyzerCasterTests extends ESTestCase {
private static final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, DEFINITION_FILES)));
private static void assertCast(Type actual, Type expected, boolean mustBeExplicit) {
Location location = new Location("dummy", 0);
if (actual.equals(expected)) {
assertFalse(mustBeExplicit);
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
assertNull(Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false));
assertNull(definition.caster.getLegalCast(location, actual, expected, false, false));
assertNull(definition.caster.getLegalCast(location, actual, expected, true, false));
return;
}
Cast cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, true, false);
Cast cast = definition.caster.getLegalCast(location, actual, expected, true, false);
assertEquals(actual, cast.from);
assertEquals(expected, cast.to);
if (mustBeExplicit) {
ClassCastException error = expectThrows(ClassCastException.class,
() -> Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false));
() -> definition.caster.getLegalCast(location, actual, expected, false, false));
assertTrue(error.getMessage().startsWith("Cannot cast"));
} else {
cast = Definition.DEFINITION.caster.getLegalCast(location, actual, expected, false, false);
cast = definition.caster.getLegalCast(location, actual, expected, false, false);
assertEquals(actual, cast.from);
assertEquals(expected, cast.to);
}
}
public void testNumericCasts() {
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.byteType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.shortType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.byteType, Definition.DEFINITION.doubleType, false);
assertCast(definition.byteType, definition.byteType, false);
assertCast(definition.byteType, definition.shortType, false);
assertCast(definition.byteType, definition.intType, false);
assertCast(definition.byteType, definition.longType, false);
assertCast(definition.byteType, definition.floatType, false);
assertCast(definition.byteType, definition.doubleType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.shortType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.shortType, Definition.DEFINITION.doubleType, false);
assertCast(definition.shortType, definition.byteType, true);
assertCast(definition.shortType, definition.shortType, false);
assertCast(definition.shortType, definition.intType, false);
assertCast(definition.shortType, definition.longType, false);
assertCast(definition.shortType, definition.floatType, false);
assertCast(definition.shortType, definition.doubleType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.intType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.intType, Definition.DEFINITION.doubleType, false);
assertCast(definition.intType, definition.byteType, true);
assertCast(definition.intType, definition.shortType, true);
assertCast(definition.intType, definition.intType, false);
assertCast(definition.intType, definition.longType, false);
assertCast(definition.intType, definition.floatType, false);
assertCast(definition.intType, definition.doubleType, false);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.longType, false);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.longType, Definition.DEFINITION.doubleType, false);
assertCast(definition.longType, definition.byteType, true);
assertCast(definition.longType, definition.shortType, true);
assertCast(definition.longType, definition.intType, true);
assertCast(definition.longType, definition.longType, false);
assertCast(definition.longType, definition.floatType, false);
assertCast(definition.longType, definition.doubleType, false);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.longType, true);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.floatType, false);
assertCast(Definition.DEFINITION.floatType, Definition.DEFINITION.doubleType, false);
assertCast(definition.floatType, definition.byteType, true);
assertCast(definition.floatType, definition.shortType, true);
assertCast(definition.floatType, definition.intType, true);
assertCast(definition.floatType, definition.longType, true);
assertCast(definition.floatType, definition.floatType, false);
assertCast(definition.floatType, definition.doubleType, false);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.byteType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.shortType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.intType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.longType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.floatType, true);
assertCast(Definition.DEFINITION.doubleType, Definition.DEFINITION.doubleType, false);
assertCast(definition.doubleType, definition.byteType, true);
assertCast(definition.doubleType, definition.shortType, true);
assertCast(definition.doubleType, definition.intType, true);
assertCast(definition.doubleType, definition.longType, true);
assertCast(definition.doubleType, definition.floatType, true);
assertCast(definition.doubleType, definition.doubleType, false);
}
}

View File

@ -37,6 +37,9 @@ import static org.hamcrest.Matchers.startsWith;
*/
public class BaseClassTests extends ScriptTestCase {
private final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
public abstract static class Gets {
private final String testString;
@ -66,7 +69,7 @@ public class BaseClassTests extends ScriptTestCase {
}
public void testGets() {
Compiler compiler = new Compiler(Gets.class, Definition.DEFINITION);
Compiler compiler = new Compiler(Gets.class, definition);
Map<String, Object> map = new HashMap<>();
map.put("s", 1);
@ -84,7 +87,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute();
}
public void testNoArgs() {
Compiler compiler = new Compiler(NoArgs.class, Definition.DEFINITION);
Compiler compiler = new Compiler(NoArgs.class, definition);
assertEquals(1, ((NoArgs)scriptEngine.compile(compiler, null, "1", emptyMap())).execute());
assertEquals("foo", ((NoArgs)scriptEngine.compile(compiler, null, "'foo'", emptyMap())).execute());
@ -108,13 +111,13 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(Object arg);
}
public void testOneArg() {
Compiler compiler = new Compiler(OneArg.class, Definition.DEFINITION);
Compiler compiler = new Compiler(OneArg.class, definition);
Object rando = randomInt();
assertEquals(rando, ((OneArg)scriptEngine.compile(compiler, null, "arg", emptyMap())).execute(rando));
rando = randomAlphaOfLength(5);
assertEquals(rando, ((OneArg)scriptEngine.compile(compiler, null, "arg", emptyMap())).execute(rando));
Compiler noargs = new Compiler(NoArgs.class, Definition.DEFINITION);
Compiler noargs = new Compiler(NoArgs.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, () ->
scriptEngine.compile(noargs, null, "doc", emptyMap()));
assertEquals("Variable [doc] is not defined.", e.getMessage());
@ -129,7 +132,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(String[] arg);
}
public void testArrayArg() {
Compiler compiler = new Compiler(ArrayArg.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ArrayArg.class, definition);
String rando = randomAlphaOfLength(5);
assertEquals(rando, ((ArrayArg)scriptEngine.compile(compiler, null, "arg[0]", emptyMap())).execute(new String[] {rando, "foo"}));
}
@ -139,7 +142,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(int[] arg);
}
public void testPrimitiveArrayArg() {
Compiler compiler = new Compiler(PrimitiveArrayArg.class, Definition.DEFINITION);
Compiler compiler = new Compiler(PrimitiveArrayArg.class, definition);
int rando = randomInt();
assertEquals(rando, ((PrimitiveArrayArg)scriptEngine.compile(compiler, null, "arg[0]", emptyMap())).execute(new int[] {rando, 10}));
}
@ -149,7 +152,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(Object[] arg);
}
public void testDefArrayArg() {
Compiler compiler = new Compiler(DefArrayArg.class, Definition.DEFINITION);
Compiler compiler = new Compiler(DefArrayArg.class, definition);
Object rando = randomInt();
assertEquals(rando, ((DefArrayArg)scriptEngine.compile(compiler, null, "arg[0]", emptyMap())).execute(new Object[] {rando, 10}));
rando = randomAlphaOfLength(5);
@ -167,7 +170,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract boolean needsD();
}
public void testManyArgs() {
Compiler compiler = new Compiler(ManyArgs.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ManyArgs.class, definition);
int rando = randomInt();
assertEquals(rando, ((ManyArgs)scriptEngine.compile(compiler, null, "a", emptyMap())).execute(rando, 0, 0, 0));
assertEquals(10, ((ManyArgs)scriptEngine.compile(compiler, null, "a + b + c + d", emptyMap())).execute(1, 2, 3, 4));
@ -195,7 +198,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(String... arg);
}
public void testVararg() {
Compiler compiler = new Compiler(VarargTest.class, Definition.DEFINITION);
Compiler compiler = new Compiler(VarargTest.class, definition);
assertEquals("foo bar baz", ((VarargTest)scriptEngine.compile(compiler, null, "String.join(' ', Arrays.asList(arg))", emptyMap()))
.execute("foo", "bar", "baz"));
}
@ -211,7 +214,7 @@ public class BaseClassTests extends ScriptTestCase {
}
}
public void testDefaultMethods() {
Compiler compiler = new Compiler(DefaultMethods.class, Definition.DEFINITION);
Compiler compiler = new Compiler(DefaultMethods.class, definition);
int rando = randomInt();
assertEquals(rando, ((DefaultMethods)scriptEngine.compile(compiler, null, "a", emptyMap())).execute(rando, 0, 0, 0));
assertEquals(rando, ((DefaultMethods)scriptEngine.compile(compiler, null, "a", emptyMap())).executeWithASingleOne(rando, 0, 0));
@ -225,7 +228,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract void execute(Map<String, Object> map);
}
public void testReturnsVoid() {
Compiler compiler = new Compiler(ReturnsVoid.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ReturnsVoid.class, definition);
Map<String, Object> map = new HashMap<>();
((ReturnsVoid)scriptEngine.compile(compiler, null, "map.a = 'foo'", emptyMap())).execute(map);
assertEquals(singletonMap("a", "foo"), map);
@ -244,7 +247,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract boolean execute();
}
public void testReturnsPrimitiveBoolean() {
Compiler compiler = new Compiler(ReturnsPrimitiveBoolean.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ReturnsPrimitiveBoolean.class, definition);
assertEquals(true, ((ReturnsPrimitiveBoolean)scriptEngine.compile(compiler, null, "true", emptyMap())).execute());
assertEquals(false, ((ReturnsPrimitiveBoolean)scriptEngine.compile(compiler, null, "false", emptyMap())).execute());
@ -286,7 +289,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract int execute();
}
public void testReturnsPrimitiveInt() {
Compiler compiler = new Compiler(ReturnsPrimitiveInt.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ReturnsPrimitiveInt.class, definition);
assertEquals(1, ((ReturnsPrimitiveInt)scriptEngine.compile(compiler, null, "1", emptyMap())).execute());
assertEquals(1, ((ReturnsPrimitiveInt)scriptEngine.compile(compiler, null, "(int) 1L", emptyMap())).execute());
@ -328,7 +331,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract float execute();
}
public void testReturnsPrimitiveFloat() {
Compiler compiler = new Compiler(ReturnsPrimitiveFloat.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ReturnsPrimitiveFloat.class, definition);
assertEquals(1.1f, ((ReturnsPrimitiveFloat)scriptEngine.compile(compiler, null, "1.1f", emptyMap())).execute(), 0);
assertEquals(1.1f, ((ReturnsPrimitiveFloat)scriptEngine.compile(compiler, null, "(float) 1.1d", emptyMap())).execute(), 0);
@ -359,7 +362,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract double execute();
}
public void testReturnsPrimitiveDouble() {
Compiler compiler = new Compiler(ReturnsPrimitiveDouble.class, Definition.DEFINITION);
Compiler compiler = new Compiler(ReturnsPrimitiveDouble.class, definition);
assertEquals(1.0, ((ReturnsPrimitiveDouble)scriptEngine.compile(compiler, null, "1", emptyMap())).execute(), 0);
assertEquals(1.0, ((ReturnsPrimitiveDouble)scriptEngine.compile(compiler, null, "1L", emptyMap())).execute(), 0);
@ -393,7 +396,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(String foo);
}
public void testNoArgumentsConstant() {
Compiler compiler = new Compiler(NoArgumentsConstant.class, Definition.DEFINITION);
Compiler compiler = new Compiler(NoArgumentsConstant.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertThat(e.getMessage(), startsWith(
@ -406,7 +409,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(String foo);
}
public void testWrongArgumentsConstant() {
Compiler compiler = new Compiler(WrongArgumentsConstant.class, Definition.DEFINITION);
Compiler compiler = new Compiler(WrongArgumentsConstant.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertThat(e.getMessage(), startsWith(
@ -419,7 +422,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(String foo);
}
public void testWrongLengthOfArgumentConstant() {
Compiler compiler = new Compiler(WrongLengthOfArgumentConstant.class, Definition.DEFINITION);
Compiler compiler = new Compiler(WrongLengthOfArgumentConstant.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertThat(e.getMessage(), startsWith("[" + WrongLengthOfArgumentConstant.class.getName() + "#ARGUMENTS] has length [2] but ["
@ -431,7 +434,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(UnknownArgType foo);
}
public void testUnknownArgType() {
Compiler compiler = new Compiler(UnknownArgType.class, Definition.DEFINITION);
Compiler compiler = new Compiler(UnknownArgType.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertEquals("[foo] is of unknown type [" + UnknownArgType.class.getName() + ". Painless interfaces can only accept arguments "
@ -443,7 +446,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract UnknownReturnType execute(String foo);
}
public void testUnknownReturnType() {
Compiler compiler = new Compiler(UnknownReturnType.class, Definition.DEFINITION);
Compiler compiler = new Compiler(UnknownReturnType.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertEquals("Painless can only implement execute methods returning a whitelisted type but [" + UnknownReturnType.class.getName()
@ -455,7 +458,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(UnknownArgTypeInArray[] foo);
}
public void testUnknownArgTypeInArray() {
Compiler compiler = new Compiler(UnknownArgTypeInArray.class, Definition.DEFINITION);
Compiler compiler = new Compiler(UnknownArgTypeInArray.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "1", emptyMap()));
assertEquals("[foo] is of unknown type [" + UnknownArgTypeInArray.class.getName() + ". Painless interfaces can only accept "
@ -467,7 +470,7 @@ public class BaseClassTests extends ScriptTestCase {
public abstract Object execute(boolean foo);
}
public void testTwoExecuteMethods() {
Compiler compiler = new Compiler(TwoExecuteMethods.class, Definition.DEFINITION);
Compiler compiler = new Compiler(TwoExecuteMethods.class, definition);
Exception e = expectScriptThrows(IllegalArgumentException.class, false, () ->
scriptEngine.compile(compiler, null, "null", emptyMap()));
assertEquals("Painless can only implement interfaces that have a single method named [execute] but ["

View File

@ -25,6 +25,7 @@ import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.script.ScriptException;
import java.io.IOException;
import java.util.Collections;
import java.util.Map;
import static java.util.Collections.singletonList;
@ -34,7 +35,8 @@ import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.not;
public class DebugTests extends ScriptTestCase {
private final Definition definition = Definition.DEFINITION;
private final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
public void testExplain() {
// Debug.explain can explain an object

View File

@ -24,6 +24,7 @@ import org.objectweb.asm.util.Textifier;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
/** quick and dirty tools for debugging */
final class Debugger {
@ -39,7 +40,9 @@ final class Debugger {
PrintWriter outputWriter = new PrintWriter(output);
Textifier textifier = new Textifier();
try {
new Compiler(iface, Definition.DEFINITION).compile("<debugging>", source, settings, textifier);
new Compiler(iface, new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES))))
.compile("<debugging>", source, settings, textifier);
} catch (Exception e) {
textifier.print(outputWriter);
e.addSuppressed(new Exception("current bytecode: \n" + output));

View File

@ -30,7 +30,8 @@ import java.util.HashMap;
import org.elasticsearch.test.ESTestCase;
public class DefBootstrapTests extends ESTestCase {
private final Definition definition = Definition.DEFINITION;
private final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
/** calls toString() on integers, twice */
public void testOneType() throws Throwable {

View File

@ -36,6 +36,7 @@ import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@ -44,7 +45,6 @@ import java.util.function.Consumer;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.toList;
import static org.elasticsearch.painless.Definition.DEFINITION;
/**
* Generates an API reference from the method and type whitelists in {@link Definition}.
@ -68,7 +68,9 @@ public class PainlessDocGenerator {
Files.newOutputStream(indexPath, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE),
false, StandardCharsets.UTF_8.name())) {
emitGeneratedWarning(indexStream);
List<Type> types = DEFINITION.allSimpleTypes().stream().sorted(comparing(t -> t.name)).collect(toList());
List<Type> types = new Definition(Collections.singletonList(
WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES))).
allSimpleTypes().stream().sorted(comparing(t -> t.name)).collect(toList());
for (Type type : types) {
if (type.clazz.isPrimitive()) {
// Primitives don't have methods to reference

View File

@ -33,6 +33,7 @@ import org.junit.Before;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@ -91,7 +92,8 @@ public abstract class ScriptTestCase extends ESTestCase {
public Object exec(String script, Map<String, Object> vars, Map<String,String> compileParams, Scorer scorer, boolean picky) {
// test for ambiguity errors before running the actual script if picky is true
if (picky) {
Definition definition = Definition.DEFINITION;
Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
ScriptClassInfo scriptClassInfo = new ScriptClassInfo(definition, GenericElasticsearchScript.class);
CompilerSettings pickySettings = new CompilerSettings();
pickySettings.setPicky(true);

View File

@ -33,10 +33,12 @@ import org.elasticsearch.painless.Locals.Variable;
import org.elasticsearch.painless.Location;
import org.elasticsearch.painless.Operation;
import org.elasticsearch.painless.ScriptClassInfo;
import org.elasticsearch.painless.WhitelistLoader;
import org.elasticsearch.painless.antlr.Walker;
import org.elasticsearch.test.ESTestCase;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -48,7 +50,8 @@ import static org.elasticsearch.painless.node.SSource.MainMethodReserved;
* Tests {@link Object#toString} implementations on all extensions of {@link ANode}.
*/
public class NodeToStringTests extends ESTestCase {
private final Definition definition = Definition.DEFINITION;
private final Definition definition = new Definition(
Collections.singletonList(WhitelistLoader.loadFromResourceFiles(Definition.class, Definition.DEFINITION_FILES)));
public void testEAssignment() {
assertToString(
@ -161,12 +164,12 @@ public class NodeToStringTests extends ESTestCase {
public void testECast() {
Location l = new Location(getTestName(), 0);
AExpression child = new EConstant(l, "test");
Cast cast = Cast.standard(Definition.DEFINITION.StringType, Definition.DEFINITION.IntegerType, true);
Cast cast = Cast.standard(definition.StringType, definition.IntegerType, true);
assertEquals("(ECast java.lang.Integer (EConstant String 'test'))", new ECast(l, child, cast).toString());
l = new Location(getTestName(), 1);
child = new EBinary(l, Operation.ADD, new EConstant(l, "test"), new EConstant(l, 12));
cast = Cast.standard(Definition.DEFINITION.IntegerType, Definition.DEFINITION.BooleanType, true);
cast = Cast.standard(definition.IntegerType, definition.BooleanType, true);
assertEquals("(ECast java.lang.Boolean (EBinary (EConstant String 'test') + (EConstant Integer 12)))",
new ECast(l, child, cast).toString());
}
@ -396,7 +399,7 @@ public class NodeToStringTests extends ESTestCase {
public void testPSubBrace() {
Location l = new Location(getTestName(), 0);
PSubBrace node = new PSubBrace(l, Definition.DEFINITION.intType, new ENumeric(l, "1", 10));
PSubBrace node = new PSubBrace(l, definition.intType, new ENumeric(l, "1", 10));
node.prefix = new EVariable(l, "a");
assertEquals("(PSubBrace (EVariable a) (ENumeric 1))", node.toString());
}
@ -762,7 +765,7 @@ public class NodeToStringTests extends ESTestCase {
public void testSSubEachArray() {
Location l = new Location(getTestName(), 0);
Variable v = new Variable(l, "test", Definition.DEFINITION.intType, 5, false);
Variable v = new Variable(l, "test", definition.intType, 5, false);
AExpression e = new ENewArray(l, "int", Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3)), true);
SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5))));
SSubEachArray node = new SSubEachArray(l, v, e, b);
@ -774,7 +777,7 @@ public class NodeToStringTests extends ESTestCase {
public void testSSubEachIterable() {
Location l = new Location(getTestName(), 0);
Variable v = new Variable(l, "test", Definition.DEFINITION.intType, 5, false);
Variable v = new Variable(l, "test", definition.intType, 5, false);
AExpression e = new EListInit(l, Arrays.asList(new EConstant(l, 1), new EConstant(l, 2), new EConstant(l, 3)));
SBlock b = new SBlock(l, singletonList(new SReturn(l, new EConstant(l, 5))));
SSubEachIterable node = new SSubEachIterable(l, v, e, b);