AnnotationBasedPersistentProperty.validateAnnotation NullPointerException on project-specific annotations.
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>2.6.0-SNAPSHOT</version>
I hit this when running the tests of spring-data-couchbase project with JDK11 and adding a java-module.java. I assume there is some sort of introspection failure.
mergedAnnotation passed into validateAnnotation and the NPE occurs when candidate is dereferenced.
https://github.com/spring-projects/spring-data-commons/blob/db8431ee41b3b73dd87364de9c6cff158790452e/src/main/java/org/springframework/data/mapping/model/AnnotationBasedPersistentProperty.java#L125
It's the .orElse((Object)null) that gets returned.
return !AnnotationFilter.PLAIN.matches(annotationType) && !AnnotationsScanner.hasPlainJavaAnnotationsOnly(element) ? (Annotation)getAnnotations(element).get(annotationType, (Predicate)null, MergedAnnotationSelectors.firstDirectlyDeclared()).synthesize(MergedAnnotation::isPresent).orElse((Object)null) : element.getDeclaredAnnotation(annotationType);
Comment From: mikereiche
Down in the bowels of AttributeMethods
:
boolean isValid(Annotation annotation) {
this.assertAnnotation(annotation);
for(int i = 0; i < this.size(); ++i) {
if (this.canThrowTypeNotPresentException(i)) {
try {
this.get(i).invoke(annotation);
} catch (Throwable var4) {
return false;
}
}
}
return true;
}
The exception thrown here is swallowed, but it gives the exact action necessary to avoid it.
class org.springframework.core.annotation.AttributeMethods (in module spring.core) cannot access interface org.springframework.data.couchbase.core.mapping.id.GeneratedValue (in module spring.data.couchbase) because module spring.data.couchbase does not export org.springframework.data.couchbase.core.mapping.id to module spring.core
Comment From: mikereiche
Exception looks like this:
Caused by: java.lang.NullPointerException: null
at spring.data.commons@2.6.0-20210713.121642-36/org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.validateAnnotation(AnnotationBasedPersistentProperty.java:164)
at spring.data.commons@2.6.0-20210713.121642-36/org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.lambda$populateAnnotationCache$10(AnnotationBasedPersistentProperty.java:144)
at java.base/java.util.Optional.ifPresent(Optional.java:183)
at spring.data.commons@2.6.0-20210713.121642-36/org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.populateAnnotationCache(AnnotationBasedPersistentProperty.java:137)
at spring.data.commons@2.6.0-20210713.121642-36/org.springframework.data.mapping.model.AnnotationBasedPersistentProperty.<init>(AnnotationBasedPersistentProperty.java:103)
at spring.data.couchbase/org.springframework.data.couchbase.core.mapping.BasicCouchbasePersistentProperty.<init>(BasicCouchbasePersistentProperty.java:58)
Comment From: sbrannen
The exception thrown here is swallowed, but it gives the exact action necessary to avoid it.
What happens if you add a suitable --add-opens
declaration?
Comment From: mikereiche
Then it works fine. But because the original exception is swallowed and results in an NPE, what should be a trivial diagnosis becomes an extended session in the debugger.
Comment From: jhoeller
The given scenario has effectively been addressed through #29448 already, avoiding reflection for annotation attribute retrieval to begin with. Even non-exported annotation types can be introspected for certain purposes that way, not leading to IllegalAccessExceptions in regular scenarios. I have nevertheless revised IllegalAccessException handling for the fallback reflection code path there.
As a bonus, we also avoid reflection for TypeVariable comparisons now (which typically happen during annotation retrieval on common classes and methods), and we log a clearer-worded message for annotation attribute retrieval failure at info level (e.g. on Google App Engine in case of a late-occurring TypeNotPresentException, logged at the same level as an early-occurring TypeNotPresentException on a regular JVM now).