Skip to content

java.lang.NoClassDefFoundError: javax/inject/Inject: javax.inject.Inject when upgrading to Spring Boot 3.3.1 #1948

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

Closed
raman-khrapavitski opened this issue Jun 27, 2024 · 16 comments · Fixed by #1983
Assignees
Labels
type: bug A general bug

Comments

@raman-khrapavitski
Copy link

raman-khrapavitski commented Jun 27, 2024

Hi, our team upgraded to Spring Boot 3.3.1 and are running into a compilation error with:
java.lang.NoClassDefFoundError: javax/inject/Inject: javax.inject.Inject

Here is sample of project where issue can be reproduced - link

Looks like this problem similar to this closed issue: #1926

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jun 27, 2024
@mikereiche
Copy link
Collaborator

Yes. I see the issue. Add this to your dependencies :

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
        <scope>compile</scope>
    </dependency>

@raman-khrapavitski
Copy link
Author

Thank you.

@mikereiche mikereiche added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 13, 2024
@mfarkan
Copy link

mfarkan commented Aug 15, 2024

Hello, is there any plan to fix this issue?

@wilkinsona
Copy link
Member

wilkinsona commented Oct 10, 2024

@mikereiche could you please consider reverting this change? It breaks Spring Boot's build as javax.inject:inject is a prohibited dependency. We have this restriction in place as, given Boot's Jakarta EE 9 baseline, jakarta.inject:inject should be used instead. We can exclude the dependency in Boot to get the build working again, but that feels like we'd be masking an underlying problem rather than resolving it at source.

It's also unusual that javax.inject:inject is excluded when depending on querydsl-apt and then declared again as a compile dependency. If javax.inject:inject really belongs on the compile classpath (IMO, it doesn't), the exclusion can be removed, AFAICT.

@mikereiche
Copy link
Collaborator

mikereiche commented Oct 10, 2024

Looking...

@mikereiche
Copy link
Collaborator

Any ideas how to avoid the issue in the original post?

Hi, our team upgraded to Spring Boot 3.3.1 and are running into a compilation error with:
java.lang.NoClassDefFoundError: javax/inject/Inject: javax.inject.Inject

@mikereiche
Copy link
Collaborator

Reverted.

@mikereiche mikereiche reopened this Oct 10, 2024
@wilkinsona
Copy link
Member

@raman-khrapavitski what version of Spring Boot were you using prior to the upgrade? I'd like to understand exactly what changed to cause the problem.

@mikereiche Fundamentally, the problem is that QueryDSL, despite using the jakarta qualifier, has a hardcoded dependency on javax.inject.Inject in its codegen module . Ideally, that code would be written defensively so it worked without javax.inject.Inject on the classpath. It could also support jakarta.inject.Inject in a defensive manner.

I'm not sure how likely any changes to QueryDSL are at this point so we may need to figure out a compromise that works with its current state.

Something else to consider here are the forthcoming changes to annotation processing. Java 21 emits a note warning about a future change in behavior. That note is:

Note: Annotation processing is enabled because one or more processors were found
  on the class path. A future release of javac may disable annotation processing
  unless at least one processor is specified by name (-processor), or a search
  path is specified (--processor-path, --processor-module-path), or annotation
  processing is enabled explicitly (-proc:only, -proc:full).
  Use -Xlint:-options to suppress this message.
  Use -proc:none to disable annotation processing.

This means that those using Java 21 and later are likely going to want to configure annotation processors and "normal" compile dependencies separately. For Gradle users, that would mean using the annotationProcessor configuration. Ideally, such dependencies would contain the bare minimum that's needed for annotation processing so it may help with future proofing for Spring Data Couchbase to introduce a separate annotation processing module for this purpose and the querydsl-apt dependency could then be removed from the "core" module. I realise this is a non-trivial change, though, not least because SDC is currently a single-module project.

@mikereiche
Copy link
Collaborator

@wilkinsona - Andy I've gone around (unsuccessfully) a few times with this starting at with #1917, #1926, #1929, #1948, #1987

So far the best I've come up with where the customer needs to add javax.inject dependency to their project if they want to use querydsl-codegen.

Going back to the beginning - why is javax.inject not allowed by spring-boot? I understand that spring-boot now uses jakarta, but that shouldn't rule out something else using javax.inject. Is there are security issue?

@mikereiche
Copy link
Collaborator

mikereiche commented Oct 11, 2024

Note: Annotation processing is enabled because one or more processors were found
on the class path.

This seems to be what is causing the user issues. Even though they don't have any annotated classes, its still calling the annotation processor because it found it on the classpath.

I thought I handled this by emitting a warning from the annotation processor and exiting nicely.
Edit: upon further testing, even though the CouchbaseAnnotationProcessor.process() returns nicely, some other AnnotationProcessor in the classpath does not.

Caused by: java.lang.ClassNotFoundException: javax.inject.Inject
at java.net.URLClassLoader.findClass (URLClassLoader.java:445)
at java.lang.ClassLoader.loadClass (ClassLoader.java:587)
at java.lang.ClassLoader.loadClass (ClassLoader.java:520)
at com.querydsl.codegen.AbstractModule.createInstance (AbstractModule.java:125)
at com.querydsl.codegen.AbstractModule.get (AbstractModule.java:95)
at com.querydsl.apt.DefaultConfiguration.getTypeMappings (DefaultConfiguration.java:480)
at com.querydsl.apt.AbstractQuerydslProcessor.process (AbstractQuerydslProcessor.java:85)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor (JavacProcessingEnvironment.java:1023)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs (JavacProcessingEnvironment.java:939)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run (JavacProcessingEnvironment.java:1267)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing (JavacProcessingEnvironment.java:1382)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations (JavaCompiler.java:1234)
at com.sun.tools.javac.main.JavaCompiler.compile (JavaCompiler.java:916)

@mikereiche
Copy link
Collaborator

mikereiche commented Oct 12, 2024

In the sample repo provided by the user - the issue can be avoided by skipping the annotation processing

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <configuration>
                <proc>none</proc>
            </configuration>
        </plugin>
    </plugins>
</build>

@wilkinsona
Copy link
Member

wilkinsona commented Oct 12, 2024

why is javax.inject not allowed by spring-boot? I understand that spring-boot now uses jakarta, but that shouldn't rule out something else using javax.inject

There's no security issue but we don't want it to be on the classpath by default. The intent here is to avoid causing confusion where a user tries to use javax.inject.Inject and is then surprised when it has no effect. It's fine if they then add a separate dependency on it either directly or transitively as they're effectively opting in at the point, we just want the out-of-the-box experience to have an EE9 baseline.

@mikereiche
Copy link
Collaborator

we don't want it to be on the classpath by default. The intent here is to avoid causing confusion where a user tries to use javax.inject.Inject and is then surprised when it has no effect.

To prevent a user from using @javax.inject.Inject (or Name etc) instead of the jakarta.inject.Inject etc? What about com.mycompany.Inject? Are we going to prohibit using any class name that is already used?

for Spring Data Couchbase to introduce a separate annotation processing module for this purpose and the querydsl-apt dependency could then be removed from the "core" module. I realise this is a non-trivial change, though, not least because SDC is currently a single-module project.

I got my hands slapped last time I tried that - #1514

@wilkinsona
Copy link
Member

To prevent a user from using @javax.inject.Inject (or Name etc) instead of the jakarta.inject.Inject etc? What about com.mycompany.Inject? Are we going to prohibit using any class name that is already used?

The concern is specifically with @javax.inject.*.

I got my hands slapped last time I tried that

I think @mp911de's concern there was that the changes introduced a dependency cycle between the Spring Data Couchbase repository and the Spring Boot repository. I share Mark's concern as we want to avoid cycles between repository.

Separating an annotation processing module out of the current, single core module would not introduce a dependency cycle. It wouldn't change any of the current dependencies, just restructure things so that some of them are isolated in a separate module that's specific to annotation processing. Of course, Mark may have other grounds for objection here, and any change should be discussed with him, but I would expect any objection to be different to the one raised with #1514.

@mp911de
Copy link
Member

mp911de commented Oct 16, 2024

I left a comment on #1990. MongoDB ships with an annotation processor that doesn't cause that sort of trouble. See #1990 (comment) for how MongoDB defines its annotation processor and I highly suggest following that path instead of tearing the Spring Data Couchbase module apart just a few days before the RC1 release.

@mikereiche
Copy link
Collaborator

mikereiche commented Oct 18, 2024

Fixed in 5.4.0-RC1, 5.3.5, 5.2.11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants