-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot invoke "javax.lang.model.element.ExecutableElement.getAnnotationMirrors()" because the return value of "javax.lang.model.element.RecordComponentElement.getAccessor()" is null #139
Comments
I'll see what I can do. But, please provide a reproducible case. |
Youri co-worker here. I don't have a reproducer yet but I have been able to use a debugger to get a glimpse of what is going on. We use @RecordInterface to define a record from an interface @RecordInterface
interface Conf {
int maxConcurrency( );
} RecordBuilder generate the following class @Generated("io.soabase.recordbuilder.core.RecordInterface")
@RecordBuilder
public record ConfRecord(int maxConcurrency) implements Conf, ConfRecordBuilder.With {} I'm able to observe that the TypeElement argument passed to buildRecordComponents correspond to ConfRecord. I also observe that maxConcurrency's accessor is null.
I see three options:
|
I just checked com.sun.tools.javac.code.Symbol.ClassSymbol#getRecordComponent(com.sun.tools.javac.tree.JCTree.JCVariableDecl, boolean, com.sun.tools.javac.util.List<com.sun.tools.javac.tree.JCTree.JCAnnotation>) implementation (Zulu 17.0.4) public RecordComponent getRecordComponent(JCVariableDecl var, boolean addIfMissing, List<JCAnnotation> annotations) {
RecordComponent toRemove = null;
for (RecordComponent rc : recordComponents) {
/* it could be that a record erroneously declares two record components with the same name, in that
* case we need to use the position to disambiguate
*/
if (rc.name == var.name && var.pos == rc.pos) {
if (rc.type.hasTag(TypeTag.ERROR) && !var.sym.type.hasTag(TypeTag.ERROR)) {
// Found a record component with an erroneous type: save it so that it can be removed later.
// If the class type of the record component is generated by annotation processor, it should
// use the new actual class type and symbol instead of the old dummy ErrorType.
toRemove = rc;
} else {
// Found a good record component: just return.
return rc;
}
}
}
RecordComponent rc = null;
if (toRemove != null) {
// Found a record component with an erroneous type: remove it and create a new one
recordComponents = List.filter(recordComponents, toRemove);
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, annotations));
} else if (addIfMissing) {
// Didn't find the record component: create one.
recordComponents = recordComponents.append(rc = new RecordComponent(var.sym, annotations));
}
return rc;
} It seems to avoid registering duplicates unless (name, pos) don't match. I observe that the entry related to the record has pos = -1 but the entry related to the interface has pos = 387. It is also unclear why it work sometime and sometimes it doesn't. I figured out that if I edit an unrelated file in IntelliJ then run a Maven build it triggers the issue but I'm unsure why. I was able to check that the md5sum of the record class doesn't change. Perhaps maven / javac is able to not run the annotation processor if nothing changed on disk? |
@Randgalt Here is a reproducer https://github.com/cykl/record-builder-139-reproducer |
Thanks for this. I'll get to it soon. |
@cykl I'm unable to reproduce the problem. Can you give more details on your environment? I tried with java 17 and 19 and the example project you provided. I don't get any errors. |
Thanks for giving it a try. We deterministically get an error using Java 17, Maven 3.8 on Linux (Fedora / Ubuntu) & macOS. Here is the output on my laptop:
|
I just pushed branch |
Using this branch, the execution of trigger.sh fails with:
|
Thanks for the update @youribonnaffe - I'll spend more time on this when I can and see if I can get to the bottom of it. |
Some potentially helpful news: it turns out this reproduces in IntelliJ sometimes. If I open RecordBuilder fresh in IntelliJ and run I see the same error. So, at least I have a semi-reproducible case. |
I can now reliably reproduce this in IntelliJ by single-compiling any interface annotated with |
@youribonnaffe and @cykl As I mention above, I can now reliably reproduce the issue in IntelliJ. The problem seems to be subsequent rounds of annotation processing. javac is supposed to process the generated record from Can you please test with this branch and let me know your results?
|
Fixes #139 It seems the existence of an old .class file for the record being generated by `@RecordInterface` is exposing a bug in javac. This change checks for the existence of the class file and deletes. It's an ugly hack but seems to work.
Thanks for taking another look at it.
I also tried with jordanz/delete-vestigal-class-file-for-record-interface but this one fails with the original error:
|
Man - it seems javac is hopeless broken with what record-builder is doing here. :( I'm not sure how to handle this. @youribonnaffe out of curiosity. If you change https://github.com/cykl/record-builder-139-reproducer/blob/main/trigger.sh to do |
@Randgalt sorry it seems I missed the last message.
You mean changing the second |
Workaround for Intellj Idea (2022.3): On Run/Debug configuration, click "Edit Configuration..." -> Modify options -> Do not build before run Remember to compile project before running test |
…ll - so, find the method manually Fixes #139
I realize you've probably moved away from RecordBuilder at this point, but I may have a fix for this issue: #172 |
Thanks @Randgalt! We haven't moved away but stopped using RecordInterface until it gets resolved. I will try the fix one of those days. |
I'd really appreciate it if you can test with this fix. My solution (I don't know why I didn't think of it before) is to manually find the accessor method instead of use Update: it solves one problem but causes others it seems. javac just can't seem to handle generated records for some reason. I'll keep seeing what I can do |
I gave the reproducer a shot with #174 and unfortunately I still see the same error. |
Damn - thanks. I posted a bug report with Oracle. Let's see what comes of it. |
@youribonnaffe FYI - I created a container and am able to reproduce using the tester provided in the container (but still not in MacOS). There is a workaround until the bug is fixed in javac. Cleaning the generated sources first fixes the problem though obviously not ideal. Here's a the Maven config for it: <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>3.3.2</version>
<executions>
<execution>
<id>clean-generated</id>
<phase>validate</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
<configuration>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
<filesets>
<fileset>
<directory>${project.build.directory}/generated-sources/annotations</directory>
<includes>
<include>**/*</include>
</includes>
</fileset>
</filesets>
</configuration>
</plugin> |
We use record-builder on a project and we often get compilation errors with the following message:
Cannot invoke "javax.lang.model.element.ExecutableElement.getAnnotationMirrors()" because the return value of "javax.lang.model.element.RecordComponentElement.getAccessor()" is null
The errors happen either in Intellij IDEA or via the CLI with Maven. Running a re-build in Intellij or running the command again fixes the issue (usually a
mvn verify
).I suspect it could come from the two tools using a different JDK or compilation options and each generating slightly different bytecode. However I've made sure that the same JDK (17.0.6) is used in both cases.
I've managed to capture a stack trace below. I'm not confident about being able to provide a reproducer project but if the error message is not helpful in understanding the problem I can give it a shot.
The text was updated successfully, but these errors were encountered: