picocli icon indicating copy to clipboard operation
picocli copied to clipboard

Picocli code gen throwing java.lang.ClassCastException: class com.sun.tools.javac.code.Attribute$UnresolvedClass

Open agibsonccc opened this issue 2 years ago • 13 comments

Following up from: https://github.com/remkop/picocli/issues/1137

I am still running in to this with picocli 4.6.1: https://gist.github.com/agibsonccc/0e90c40e765e417d927de3c35ee6fabc

I am using graalvm jdk 11: graalvm-ce-java11-21.2.0

agibsonccc avatar Sep 26 '21 11:09 agibsonccc

Looking at the error (repeated full stack trace below):

 FATAL ERROR: java.lang.ClassCastException: class com.sun.tools.javac.code.Attribute$UnresolvedClass cannot be cast to class com.sun.tools.javac.code.Attribute$Class (com.sun.tools.javac.code.Attribute$UnresolvedClass and com.sun.tools.javac.code.Attribute$Class are in module jdk.compiler of loader 'app')
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker$ValueVisitor.visitArray(AnnotationProxyMaker.java:192)
[ERROR]         at jdk.compiler/com.sun.tools.javac.code.Attribute$Array.accept(Attribute.java:327)
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker$ValueVisitor.getValue(AnnotationProxyMaker.java:167)
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker.generateValue(AnnotationProxyMaker.java:145)
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker.getAllReflectedValues(AnnotationProxyMaker.java:104)
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker.generateAnnotation(AnnotationProxyMaker.java:90)
[ERROR]         at jdk.compiler/com.sun.tools.javac.model.AnnotationProxyMaker.generateAnnotation(AnnotationProxyMaker.java:81)
[ERROR]         at jdk.compiler/com.sun.tools.javac.code.AnnoConstruct.getAnnotation(AnnoConstruct.java:185)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.updateCommandSpecFromCommandAnnotation(AbstractCommandSpecProcessor.java:335)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.updateCommandSpecFromTypeElement(AbstractCommandSpecProcessor.java:276)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.access$100(AbstractCommandSpecProcessor.java:92)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor$1.visitType(AbstractCommandSpecProcessor.java:244)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor$1.visitType(AbstractCommandSpecProcessor.java:241)
[ERROR]         at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.accept(Symbol.java:1447)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.buildCommand(AbstractCommandSpecProcessor.java:241)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.buildCommands(AbstractCommandSpecProcessor.java:226)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.tryProcess(AbstractCommandSpecProcessor.java:185)
[ERROR]         at picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.process(AbstractCommandSpecProcessor.java:165)
[ERROR]         at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:980)
[ERROR]         at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:896)

in that stacktrace, to me the most interesting line is the last line of picocli code, which is this:

picocli.codegen.annotation.processing.AbstractCommandSpecProcessor.updateCommandSpecFromCommandAnnotation(AbstractCommandSpecProcessor.java:335)

Looking at what AbstractCommandSpecProcessor.java:335 does:

Command cmd = element.getAnnotation(Command.class);

So, getting the annotation class picocli.CommandLine.Command results in a ClassCastException because (judging from Attribute$UnresolvedClass) the Command class cannot be resolved.

My guess is that the picocli jar is not in the classpath, only the picocli-codegen jar is in the classpath. Can you confirm and try again after adding the picocli jar to the classpath for the annotation processor?

remkop avatar Sep 27 '21 03:09 remkop

@agibsonccc did that solve the issue?

remkop avatar Sep 28 '21 01:09 remkop

@remkop actually picocli was on the classpath. The only fix was removing codegen from the classpath. For now I just manually extracted the graalvm information I needed. I'll hope to add the codegen module back at a later date.

agibsonccc avatar Sep 28 '21 02:09 agibsonccc

@agibsonccc I still suspect it is a build config issue. Can you post your maven or gradle config here?

remkop avatar Sep 28 '21 04:09 remkop

@remkop let me see if I can build a minimal reproducer project for you to verify the issue.

agibsonccc avatar Sep 29 '21 23:09 agibsonccc

Are you using Gradle? I had a similar issue once but it is a long time ago and I don't remember exactly, but it had to do with the classpath for the annotation processor being different from the classpath for the rest of the compilation.

I can imagine this error happening if --processor-path only contains picocli-codegen (but not picocli).

You may be able to verify this by adding this snippet to your build.gradle:

tasks.withType(JavaCompile) {
    doFirst {
        println "AnnotationProcessorPath for $name is ${options.getAnnotationProcessorPath().getFiles()}"
    }
}

remkop avatar Sep 30 '21 01:09 remkop

@remkop actually no. Just maven with picocli and codegen. You can actually see the project's reflect config json here: https://github.com/KonduitAI/konduit-serving/blob/master/konduit-serving-config-creator/src/main/resources/META-INF/native-image/reflect-config.json#L35

The pom including the relevant native image command line can be found here: https://github.com/KonduitAI/konduit-serving/blob/master/konduit-serving-config-creator/pom.xml#L190

You can kind of see why I would want to extract a minimal project for you. I'm only using a standard picocli 4.6.1 with the 2 dependencies, nothing crazy.

agibsonccc avatar Sep 30 '21 01:09 agibsonccc

Okay great, access to your pom is helpful. Can you try adding the picocli dependency to the annotation processor path (line 177)? Something like this:

          <annotationProcessorPaths>
            <path>
              <groupId>info.picocli</groupId>
              <artifactId>picocli-codegen</artifactId>
              <version>4.6.1</version>
            </path>
            <path>
              <groupId>info.picocli</groupId>
              <artifactId>picocli</artifactId>
              <version>4.6.1</version>
            </path>
          </annotationProcessorPaths>

remkop avatar Sep 30 '21 01:09 remkop

@agibsonccc did that solve the issue?

remkop avatar Nov 13 '21 03:11 remkop

@agibsonccc did that solve the issue?

remkop avatar Jan 19 '22 08:01 remkop

Well, it solved mine between your suggestions @remkop and the parent's reflect config. Thank you.

borland502 avatar Jan 29 '22 15:01 borland502

Hey folks sorry for the late reply: when I was trying this I was using the picocli docs pretty closely and still running in to this.

agibsonccc avatar Jan 31 '22 09:01 agibsonccc

Hi @agibsonccc thanks for replying!

You mention the picocli docs, and that is also what I am interested in. The docs currently suggest this configuration:

    <annotationProcessorPaths>
      <path>
        <groupId>info.picocli</groupId>
        <artifactId>picocli-codegen</artifactId>
        <version>4.6.2</version>
      </path>
    </annotationProcessorPaths>

I was wondering if the problem you encountered would be resolved if you changed that to this instead:

          <annotationProcessorPaths>
            <path>
              <groupId>info.picocli</groupId>
              <artifactId>picocli-codegen</artifactId>
              <version>4.6.2</version>
            </path>
            <path>
              <groupId>info.picocli</groupId>
              <artifactId>picocli</artifactId>
              <version>4.6.2</version>
            </path>
          </annotationProcessorPaths>

Have you had a chance to try that and what was the result?

remkop avatar Jan 31 '22 10:01 remkop

Hey guys I ran into this issue with a different annotation processor.

It looks like this: https://bugs.openjdk.org/browse/JDK-8023548 but I have had annotation processors work fine and then suddenly fail with a similar error when doing refactoring or what not.

The issue is whatever class that is referenced in the annotation array better be available in the classpath or imported corrected. Otherwise instead of getting a compiler error about the class (symbol) not being found you get the bizarre annotation error from that bug.

So I don't know about picocli' annotations API but I'm betting it has an annotation that takes an array of classes similar to this one:

@Retention(SOURCE)
@Documented
@Target(TYPE)
public @interface MetaInfServices {
    Class<?>[] value() default void.class;
}

If I say did:

@MetaInfServices(SomeClassMissingFromClasspath.class)

You will get the bizarro exception.

So I'm betting the bug filer has some classpath issues.

agentgt avatar Sep 25 '22 14:09 agentgt

@agentgt Thanks for letting us know. I don't think there's anything that can be done about this in the picocli library, but please let me know if I am incorrect about that.

remkop avatar Sep 25 '22 20:09 remkop

@remkop that is correct that there is nothing the lib can do. I was merely knowledge sharing.

agentgt avatar Sep 27 '22 23:09 agentgt

@agentgt @remkop I haven't been able to look at this in a while but haven't bumped in to this in a while. I would go ahead and just close this. If someone else runs in to this at least they'll find this github issue.

agibsonccc avatar Sep 28 '22 02:09 agibsonccc