Description
Is your feature request related to a problem? Please describe.
The AnnotatedMember
interface does not expose a method to access its enclosing AnnotatedClass
.
Example use case: a custom annotation introspector
@Pojo(prefix="Prefix_")
public class Foo {
@Field("Name")
public int getField() {
return 42;
}
}
Suppose I would like to implement the AnnotationIntrospector#findNameForSerialization
method to return "Prefix_Name"
for the annotated method getField
.
Solution 1: access annotation directly on the declaring Class<?>
object
@Override
public PropertyName findNameForSerialization(Annotated a) {
if (a.hasAnnotation(Field.class)) {
String name = a.getAnnotation(Field.class).value();
String prefix = "";
// Try to access the prefix from the enclosing class.
if (a instanceof AnnotatedMember) {
AnnotatedMember m = (AnnotatedMember) a;
Class<?> declaringClass = m.getDeclaringClass();
if (declaringClass.isAnnotationPresent(Pojo.class)) {
prefix = declaringClass.getAnnotation(Pojo.class).prefix();
}
}
return new PropertyName(prefix + name);
}
return null;
}
Notice that, whereas I can access annotations of the Annotated
input using the conventional Jackson API, I have to go through the basic Java Class
API to access the annotation of the enclosing class.
This works for this particular use case. However, it does not work when inheritance is involved, e.g., for the following pojo:
@Pojo(prefix="Prefix_")
public interface Foo {
int getField();
public class FooImpl implements Foo {
@Field("Name")
@Override
public int getField() {
return 42;
}
}
}
It would be better if I would be able to somehow access the declaring AnnotatedClass
object instead. This is what I try to do in the following solution.
Solution 2: access annotation on the declaring AnnotatedClass
object.
@Override
public PropertyName findNameForSerialization(Annotated a) {
if (a.hasAnnotation(Field.class)) {
String name = a.getAnnotation(Field.class).value();
String prefix = "";
// Try to access the prefix from the enclosing class.
if (a instanceof AnnotatedMember) {
AnnotatedMember m = (AnnotatedMember) a;
AnnotatedClass declaringClass = (AnnotatedClass) m.getTypeContext(); // Note: `getTypeContext` is deprecated.
if (declaringClass.hasAnnotation(Pojo.class)) {
prefix = declaringClass.getAnnotation(Pojo.class).prefix();
}
}
return new PropertyName(prefix + name);
}
return null;
}
While this seems to work perfectly (even for the inheritance use case), I have to use a deprecated method getTypeContext
, and I have to cast that result into an AnnotatedClass
. I don't see a way around this though. For now, I am using this as a workaround, but ideally it would be possible to do this in a non-deprecated direct way.
Describe the solution you'd like
AnnotatedMember
should expose a method called getAnnotatedDeclaringClass()
that returns the enclosing AnnotatedClass
.
Usage example
Taking my use case from above, it could be implemented as follows:
@Override
public PropertyName findNameForSerialization(Annotated a) {
if (a.hasAnnotation(Field.class)) {
String name = a.getAnnotation(Field.class).value();
String prefix = "";
// Try to access the prefix from the enclosing class.
if (a instanceof AnnotatedMember) {
AnnotatedMember m = (AnnotatedMember) a;
AnnotatedClass declaringClass = m.getAnnotatedDeclaringClass(); // Example usage
if (declaringClass.hasAnnotation(Pojo.class)) {
prefix = declaringClass.getAnnotation(Pojo.class).prefix();
}
}
return new PropertyName(prefix + name);
}
return null;
}