jOOQ / jOOR

jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK's reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better.
http://www.jooq.org/products
Apache License 2.0
2.81k stars 376 forks source link

Cannot compile nested or additional top-level classes #71

Closed lburgazzoli closed 5 years ago

lburgazzoli commented 5 years ago

Expected behavior and actual behavior:

I have this class that is loaded and compiled through jOOR:

package com.example;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;

public class WithCustomProcessor extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        Processor ucp = new Processor() {
            public void process(Exchange exchange) throws Exception {
                String body = exchange.getIn().getBody(String.class);
                body = body.toUpperCase();
                exchange.getOut().setBody(body);
            }
        };

        from("timer:tick?period=10s")
              .setBody().constant("Hello")
            .process(ucp)
            .to("log:info");
    }
}

But when the the method configure is invoked from the compiled object, the following exception is thrown:

Exception in thread "main" java.lang.NoClassDefFoundError: com/example/WithCustomProcessor$1
    at com.example.WithCustomProcessor.configure(WithCustomProcessor.java:13)
    at com.github.lburgazzoli.JoorTest.main(JoorTest.java:15)
Caused by: java.lang.ClassNotFoundException: com.example.WithCustomProcessor$1
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 2 more

Steps to reproduce the problem:

I have a repo with a reproducer here. Running the main class will reproduce the issue.

Versions:

lukaseder commented 5 years ago

Thanks a lot for your report. Interesting observation. Of course, an individual compilation unit (Java source code unit) can produce more than one class. Not just when nesting classes, but also at the top level. We should definitely make sure those classes are loaded as well.

Will need to think about how this is fixable.

lukaseder commented 5 years ago

The workaround in your case is to use a lambda, I suspect? This should work:

package com.example;

import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.camel.builder.RouteBuilder;

public class WithCustomProcessor extends RouteBuilder {
    @Override
    public void configure() throws Exception {
        Processor ucp = exchange -> {
            String body = exchange.getIn().getBody(String.class);
            body = body.toUpperCase();
            exchange.getOut().setBody(body);
        };

        from("timer:tick?period=10s")
              .setBody().constant("Hello")
            .process(ucp)
            .to("log:info");
    }
}
lburgazzoli commented 5 years ago

Yes lambda do work

lukaseder commented 5 years ago

This was actually not that hard to fix. The compiler sends several compiled classes, we're just ignoring all of them, except for the top level class.