janino-compiler / janino

Janino is a super-small, super-fast Java™ compiler.
http://janino-compiler.github.io/janino
Other
1.25k stars 208 forks source link

Assignment conversion not possible from type InterfaceClass to type AbstractClass #212

Closed BrockZhou closed 7 months ago

BrockZhou commented 9 months ago

Hi, I meet some problem when use Janino, version 3.1.11. The return value of the MapperClass().mapper().path() method is of type BaseClass, but it appears that when processed by ScriptEvaluator, the return value of this method is considered to be the type of IBase interface. My code is as follows:

public class JaninoTest {
    public static void main(String[] args) {
        try {
            IScriptEvaluator se = new ScriptEvaluator();
            se.setReturnType(String.class);
            se.cook("import base.IBase;\n"
                     + "import base.BaseClass;\n"
                     + "import base.DerivedClass;\n"
                     + "import base.MapperClass;\n"
                     + "BaseClass o= new MapperClass().mapper().path();\n"
                     + "return o.toString();\n");
            Object res = se.evaluate(new Object[0]);
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

package base;
public abstract class BaseClass implements IBase {

    private String baseId;
    public BaseClass(){

    }

    public BaseClass(String baseId) {
        super();
        this.baseId = baseId;
    }

    public abstract BaseClass path();
    @Override
    public String toString() {
        return "BaseClass [baseId=" + baseId + "]";
    }
}

package base;
public class DerivedClass extends BaseClass {

    private String name;
    public DerivedClass() {
        super();
    }
    public DerivedClass(String baseId, String name) {
        super(baseId);
        this.name = name;
    }

    @Override
    public BaseClass path() {
        return new DerivedClass("0", "default");
    }

    @Override
    public String toString() {
        return super.toString() + "DerivedClass [name=" + name + "]";
    }

}

package base;
public interface IBase {
    IBase path();
}

package base;
public class MapperClass {
    public BaseClass mapper(){
      return new DerivedClass();
    }
}

Exception: org.codehaus.commons.compiler.CompileException: Line 5, Column 41: Assignment conversion not possible from type "base.IBase" to type "base.BaseClass" at org.codehaus.janino.UnitCompiler.compileError(UnitCompiler.java:13212) at org.codehaus.janino.UnitCompiler.assignmentConversion(UnitCompiler.java:11429) at org.codehaus.janino.UnitCompiler.access$3900(UnitCompiler.java:240) at org.codehaus.janino.UnitCompiler$7.visitRvalue(UnitCompiler.java:2813) at org.codehaus.janino.UnitCompiler$7.visitRvalue(UnitCompiler.java:2803) at org.codehaus.janino.Java$Rvalue.accept(Java.java:4498) at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:2803) at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:2790) at org.codehaus.janino.UnitCompiler.access$2700(UnitCompiler.java:240) at org.codehaus.janino.UnitCompiler$6.visitLocalVariableDeclarationStatement(UnitCompiler.java:1593) at org.codehaus.janino.UnitCompiler$6.visitLocalVariableDeclarationStatement(UnitCompiler.java:1579) at org.codehaus.janino.Java$LocalVariableDeclarationStatement.accept(Java.java:3842) at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:1579) at org.codehaus.janino.UnitCompiler.compileStatements(UnitCompiler.java:1665) at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:3713) at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:3378) at org.codehaus.janino.UnitCompiler.compileDeclaredMethods(UnitCompiler.java:1451) at org.codehaus.janino.UnitCompiler.compileDeclaredMethods(UnitCompiler.java:1424) at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:833) at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:446) at org.codehaus.janino.UnitCompiler.access$400(UnitCompiler.java:240) at org.codehaus.janino.UnitCompiler$3.visitPackageMemberClassDeclaration(UnitCompiler.java:426) at org.codehaus.janino.UnitCompiler$3.visitPackageMemberClassDeclaration(UnitCompiler.java:422) at org.codehaus.janino.Java$PackageMemberClassDeclaration.accept(Java.java:1688) at org.codehaus.janino.UnitCompiler.compile(UnitCompiler.java:422) at org.codehaus.janino.UnitCompiler.compile2(UnitCompiler.java:396) at org.codehaus.janino.UnitCompiler.access$000(UnitCompiler.java:240) at org.codehaus.janino.UnitCompiler$2.visitCompilationUnit(UnitCompiler.java:367) at org.codehaus.janino.UnitCompiler$2.visitCompilationUnit(UnitCompiler.java:365) at org.codehaus.janino.Java$CompilationUnit.accept(Java.java:371) at org.codehaus.janino.UnitCompiler.compileUnit(UnitCompiler.java:365) at org.codehaus.janino.SimpleCompiler.cook(SimpleCompiler.java:273) at org.codehaus.janino.ClassBodyEvaluator.cook(ClassBodyEvaluator.java:303) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:870) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:787) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:771) at org.codehaus.janino.ScriptEvaluator.cook2(ScriptEvaluator.java:722) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:687) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:678) at org.codehaus.janino.ScriptEvaluator.cook(ScriptEvaluator.java:618) at org.codehaus.commons.compiler.Cookable.cook(Cookable.java:82) at org.codehaus.commons.compiler.Cookable.cook(Cookable.java:77) at JaninoTester01.main(JaninoTester01.java:10)

aunkrig commented 8 months ago

Hey Brock,

I believe I fixed the bug... please test!

CU Arno

BrockZhou commented 8 months ago

Hey, Arno I had test your changes. This works well when there is no constructor in the abstract class,but when there is a constructor in the abstract class, the same exception still occurs. Actually,I want to use janino and jackson to parse json, but there is a constructor in com.fasterxml.jackson.databind.JsonNode. So I can't use long req_ts = node.path("req_ts").asLong(0l) in janino script. My code as follows, jackson-databind version 2.15.2

public class JaninoParseJson {
    public static void main(String[] args) throws CompileException, InvocationTargetException, ClassNotFoundException, JsonProcessingException {
        ScriptEvaluator se  = new ScriptEvaluator();
        se.setParameters(new String[] { "arg1" }, new Class[] { Class.forName("com.fasterxml.jackson.databind.JsonNode") });
        se.setReturnType(Long.class);
        se.cook(
                        "import com.fasterxml.jackson.databind.JsonNode;\n" +
                        "class Parse {\n" +
                         "  public static Long exec(JsonNode node){\n" +
                         "        JsonNode req_tsNode = node.path(\"req_ts\");\n" +
                         "        long req_ts = req_tsNode.asLong(0l);\n" +
                         "        while(req_ts/10000000000000l > 1 ){\n" +
                         "            req_ts = req_ts/1000;\n" +
                         "        }\n" +
                         "        return req_ts;\n" +
                         "    }" +
                        "}\n" +
                        "\n" +
                        "return new Parse().exec(arg1);"

        );
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree("{\"req_ts\": 1700552702608763600 }");
        Object result = se.evaluate(0, new Object[]{jsonNode});
        System.out.println(result);
    }
}
aunkrig commented 8 months ago

Reproduced.

Man, that's crazy... you add a CONSTRUCTOR, and then an error occurs when you invoke a FUNCTION!?

I will check.

aunkrig commented 8 months ago

Please test again.

BrockZhou commented 8 months ago

It works, thank you

aunkrig commented 8 months ago

Great! Do you need a release, or can you live with the fox on the MASTER?

BrockZhou commented 8 months ago

Yeah, I need a release. Thank you again.

aunkrig commented 8 months ago

Version 3.1.12 is out the door and includes this fix.