If spring-context-indexer is used in an application that uses @javax.transaction.Transactional (which is provided by spring-boot-starter-data-jpa), compilation will fail due to javax.interceptor.InterceptorBinding not being available.
This can be easily reproduced with a project as simple as:
plugins {
id 'java'
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
id 'org.springframework.boot' version '2.1.2.RELEASE'
}
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.h2database:h2'
annotationProcessor 'org.springframework:spring-context-indexer'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
@SpringBootApplication
@javax.transaction.Transactional
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
$ ./gradlew compileJava
> Task :compileJava FAILED
error: cannot access InterceptorBinding
class file for javax.interceptor.InterceptorBinding not found
Consult the following stack trace for details.
com.sun.tools.javac.code.Symbol$CompletionFailure: class file for javax.interceptor.InterceptorBinding not found
1 error
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 0s
1 actionable task: 1 executed
Adding the following dependency addresses the problem:
implementation 'javax.interceptor:javax.interceptor-api:1.2.2'
Since spring-boot-starter-data-jpa pulls in javax.transaction-api I believe it should also provide javax.interceptor-api having in mind the definition of javax.transaction.Transactional:
@Inherited
@InterceptorBinding // <= comes from javax.interceptor-api
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Transactional {
If
spring-context-indexeris used in an application that uses@javax.transaction.Transactional(which is provided byspring-boot-starter-data-jpa)
Isn't that more of a problem of the indexer that is browsing on an annotation that might not be available? Does the application work fine without that library? If so, I don't see why the starter should provide it.
Edit: @snicoll replied while I was writing the below. The TL;DR is that I agree with him.
Thanks for the suggestion. I am not sure that I agree that javax.interceptor-api should be provided. As far as I know, the @InterceptorBinding annotation has no effect outside a CDI environment. At runtime, the annotation is dropped when the class is loaded as required by the JLS.
We've seen a similar problem in the past with javadoc that appeared to be a regression in early versions of Java 8. I think the right place to fix this is in the JDK so that annotations that are not on the classpath are dropped during annotation processing as they are at runtime. Failing that, then I think it's something that the Indexer should tolerate. I don't think adding a runtime dependency to address an annotation-processing-specific limitation is the right thing to do.
Thanks for the feedback, both - taking your comments into consideration, I agree that this is something that indexer should be able to tolerate (regardless of the situation with JDK). I'll open an issue against Spring Framework and post the link here.
I've opened spring-projects/spring-framework#22385.
And a PR even, thanks @vpavic!