Context
I have a scenario where I am extending an annotation API from
@interface MyAnnotation {
String[] old();
}
to
@interface MyAnnotation {
String[] value();
@deprecated
String[] old() default {}
}
Here, old libraries compiled with the old annotation are still supported as the change is binary compatible. It is only that I as a framework author need to handle the case of an invocation of value() throwing an IncompleteAnnotationException.
I believe allowing this is crucial to evolution of annotations without forcing all implementors to re-compile.
Issue in Spring Core
When calling org.springframework.beans.factory.ListableBeanFactory#findAnnotationOnBean, Spring tries to build a proxy for the found annotation. In the process, spring attempts to load the value of all annotation attributes via org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler#getAttributeValue. This fails for the newly added annotation attribute as mentioned above:
java.lang.annotation.IncompleteAnnotationException: MyAnnotation missing element value
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:81)
at com.sun.proxy.$Proxy180.value(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:279) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:263) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.TypeMappedAnnotation.getValue(TypeMappedAnnotation.java:429) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.TypeMappedAnnotation.getValue(TypeMappedAnnotation.java:399) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.TypeMappedAnnotation.getAttributeValue(TypeMappedAnnotation.java:384) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.AbstractMergedAnnotation.getValue(AbstractMergedAnnotation.java:178) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler.getAttributeValue(SynthesizedMergedAnnotationInvocationHandler.java:176) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler.<init>(SynthesizedMergedAnnotationInvocationHandler.java:66) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler.createProxy(SynthesizedMergedAnnotationInvocationHandler.java:184) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.TypeMappedAnnotation.createSynthesized(TypeMappedAnnotation.java:335) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.AbstractMergedAnnotation.synthesize(AbstractMergedAnnotation.java:210) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.core.annotation.AbstractMergedAnnotation.synthesize(AbstractMergedAnnotation.java:200) [org.apache.servicemix.bundles.spring-core:5.2.0.RELEASE_1]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAnnotationOnBean(DefaultListableBeanFactory.java:680) [io.neba.spring-beans:5.2.0.RELEASE_1]
Here, I believe the implementation should not expected values to be complete. I am not even sure as to why org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler#SynthesizedMergedAnnotationInvocationHandler loads the values in the first place.
Context
I have a scenario where I am extending an annotation API from
to
Here, old libraries compiled with the old annotation are still supported as the change is binary compatible. It is only that I as a framework author need to handle the case of an invocation of value() throwing an
IncompleteAnnotationException.I believe allowing this is crucial to evolution of annotations without forcing all implementors to re-compile.
Issue in Spring Core
When calling
org.springframework.beans.factory.ListableBeanFactory#findAnnotationOnBean, Spring tries to build a proxy for the found annotation. In the process, spring attempts to load the value of all annotation attributes viaorg.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler#getAttributeValue. This fails for the newly added annotation attribute as mentioned above:Here, I believe the implementation should not expected values to be complete. I am not even sure as to why
org.springframework.core.annotation.SynthesizedMergedAnnotationInvocationHandler#SynthesizedMergedAnnotationInvocationHandlerloads the values in the first place.