kite-sdk / kite

Kite SDK
http://kitesdk.org/docs/current/
Apache License 2.0
394 stars 263 forks source link

Java command - class resolving with Java 1.8 #459

Open brunatm opened 7 years ago

brunatm commented 7 years ago

Class is not correctly resolved in ScriptEvaluator() -> FastJavaScriptEngine.compile() call. I have Java code snippet in java command:

byte[] bytes = (byte[]) record.getFirstValue("time");
long time = (Long)org.apache.phoenix.schema.types.PLong.INSTANCE.toObject(bytes);
. . .
return child.process(record);

When this is evaluated in JavaBuilder -> ScriptEvaluator I get exception: javax.script.ScriptException: Cannot compile script: ... caused by java.lang.NoSuchMethodException: edu.umd.cs.findbugs.annotations.SuppressWarnings.eval(org.kitesdk.morphline.api.Record, com.typesafe.config.Config, org.kitesdk.morphline.api.Command, org.kitesdk.morphline.api.Command, org.kitesdk.morphline.api.MorphlineContext, org.slf4j.Logger) at org.kitesdk.morphline.scriptengine.java.ScriptEvaluator.throwScriptCompilationException(ScriptEvaluator.java:141) at org.kitesdk.morphline.scriptengine.java.ScriptEvaluator.(ScriptEvaluator.java:108) at TestScriptEvaluator.main(TestScriptEvaluator.java:30) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) It fails when compiling to Java 1.8, ok when 1.6 is set. But 1.8 is required by project.

ScriptEvaluator builds up string representation of temporary Java class and calls FastJavaScriptEngine to compile it. FastJavaScriptEngine tries to find class where eval method is expected. This is the point of failure under 1.8 bytecode. Here classBytes is map of size 2 with edu.umd.cs.findbugs.annotations.SuppressWarnings and org.kitesdk.morphline.scriptengine.java.scripts.MyJavaClass1 classes. Logic of method parse() will load first of these classes which is unfortunately SuppressWarnings and so the exception NoSuchMethodException is throwed. When analyzing this I located the SuppressWarnings appears because of line: ...org.apache.phoenix.schema.types.PLong.INSTANCE.toObject(bytes); but I don't see any compilation warning which can happen here. But that is not important for this issue.

ScriptEvaluator knows the name of class which contains command code snippet and can tell this to FastJavaScriptEngine so it doesn't have to search for class. This is also workaround I used in my case (via mainClass context attribute).

Please verify such behaviour when Java 1.8 is used and consider some fix. I attached TestScriptEvaluator class which simulates this error.

https://gist.github.com/brunatm/2c7b8b7a56c4a4a5ca96167b9bdb2786

whoschek commented 7 years ago

The build (which also tests the java command) passes on java7 and java8 per https://travis-ci.org/kite-sdk/kite

Seems like this line "org.apache.phoenix.schema.types.PLong.INSTANCE.toObject(bytes)" requires the class edu.umd.cs.findbugs.annotations.SuppressWarnings on the classpath, and that SuppressWarnings class is missing on your classpath. Try adding the jar containing that SuppressWarnings class.

brunatm commented 7 years ago

This class is successfully loaded in FastJavaScriptEngine.parse() (by Launcher$AppClassLoader) so it can't be missing on classpath. In other words calling org.apache.phoenix.schema.types.PLong.INSTANCE.toObject(bytes); itself in project is not problem (no missing class). Yes, the SuppressWarnings class is loaded at the moment of .toObject() compilation but that shouldn't block ScriptEvaluator from running its code snippet (find temp. class MyJavaClass#).

(Besides that I don't see any JavaBuilder test in https://github.com/kite-sdk/kite/tree/master/kite-morphlines/kite-morphlines-core/src/test/java/org/kitesdk/morphline/stdlib)

whoschek commented 7 years ago

Tests for java command are here: https://github.com/kite-sdk/kite/blob/master/kite-morphlines/kite-morphlines-core/src/test/java/org/kitesdk/morphline/api/MorphlineTest.java#L1237-L1271
They pass on java8