question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

AnnotationIntrospector `findPropertyTypeResolver` method generic type provides Object.class as baseType instead of actual type found in AnnotatedMember

See original GitHub issue

Describe the bug I have encountered the issue where my custom AnnotationIntrospector method findPropertyTypeResolver receives JavaType baseType generic Object.class for generic method, meanwhile AnnotatedMember (AnnotatedMethod::getRawReturnType()) returns correct type

Version information 2.12.6.1

To Reproduce

interface Type {}

class Foo<T of Type> {
  private T type;

  public T getType() {
    return type;
  }
}


public class Introspector extends NopAnnotationIntrospector {
  @Override
  public TypeResolverBuilder<?> findPropertyTypeResolver(
      MapperConfig<?> config, AnnotatedMember am, JavaType baseType) {

  // am is for Foo::getType() method

    var rawClass = baseType.getRawClass(); // Object.class
    if (am instanceof AnnotatedMethod amm) {
        rawClass = amm.getRawReturnType(); // Type.class
      }
    }
 }
}

Expected behavior Additional context

I know that getType() with inside _typeContext.resolveType(_method.getGenericReturnType()) see generic variable T value as Object.class and thats the reason why baseType is Object.class, but if AnnotatedMethod knows the Type.class type it would be nice if baseType would know it too…

Issue Analytics

  • State:open
  • Created a year ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
aurimasniekiscommented, Jul 21, 2022

Thanks for the reply @cowtowncoder I managed to patch up some demo example, for some reason I was not able to make it run without spring in standalone, but that’s not really a point so I just dropped in Spring boot and managed to replicate minimal functionality.

I also had to redo the logic after I created the ticket, I needed to fetch the type depending on what context but I think I managed to make it generic for my use case.

Here is the situation I mentioned regarding Object.class

protected TypeResolverBuilder<?> resolveTypeResolver(MapperConfig<?> config, Annotated a, JavaType baseType)
  {
    var rawClass = baseType.getRawClass();
    if (rawClass.equals(Object.class)) {
      if (a instanceof AnnotatedMethod am) {
        if (am.getParameterCount() == 1) {
          rawClass = am.getRawParameterType(0);
        } else if(am.getParameterCount() == 0) {
          rawClass = am.getRawReturnType();
        }
      } else {
        rawClass = a.getRawType();
      }
    }

https://github.com/aurimasniekis/jackson-generic-instrospector/blob/main/src/main/java/org/example/jackson_generic_instrospector/ExampleIntrospector.java#L54-L64

I am pretty new to Jackson and spend many hours in debugger until I managed to make what I wanted 😅 but I hope it’s not really off the shelf 😄

0reactions
cowtowncodercommented, Jul 21, 2022

Ok, to, Type.class is unfortunately pretty useless: one cannot actually resolve generic types with only Type given because actual type binding is typically done somewhere else (resolved with what enclosing Class or Method has). Hence JavaType which is resolved representation, resolution of which requires full context.

Now, as to setter/getter: it is not actually chosen randomly… heuristic is simply that the precedence is based on “direction”: for serialization “getter” is chosen over Field or “setter”; for deserialization reverse is true (“setter” is the primary). This ordering affects priority of annotations (which are combined across all accessors), as well as type information. But beyond having this guideline, it is possible that code in some place might select “wrong” accessor. If so, selection at very least should be stable, that is, predictable given situation. It is not the case that selection would be varying across runs, for example (or platforms) – something that could happen for things like order of Fields or Methods JDK reports (which is not guaranteed to be predictable or stable).

Read more comments on GitHub >

github_iconTop Results From Across the Web

AnnotationIntrospector (jackson-databind 2.5.0 API) - FasterXML
Abstract class that defines API used for introspecting annotation-based configuration for serialization and deserialization. Separated so that different ...
Read more >
Uses of Class com.fasterxml.jackson.databind.JavaType - javadoc.io
Factory method for constructing ObjectWriter that will serialize objects using specified root type, instead of actual runtime type of value.
Read more >
Class AnnotationIntrospector - Red Hat Customer Portal
Abstract class that defines API used for introspecting annotation-based configuration for serialization and deserialization. Separated so that different ...
Read more >
Java Generics Example Tutorial - Generic Method, Class ...
Java Generic Class. We can define our own classes with generics type. A generic type is a class or interface that is parameterized...
Read more >
类 org.codehaus.jackson.type.JavaType 的使用
Contains classes needed for type introspection, mostly used by data binding ... Method for reading sequence of Objects from parser stream, all with...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found