Search code examples
javaserializationjacksonmixins

Jackson key deserializer not being called/recognized


I keep getting this error even after I have implemented the custom key deserializer. The following error occurred during the invocation of the handlers chain:

JsonMappingException with message 'Can not find a (Map) Key deserializer for type 
[simple type, class com.abc.xyz.da.kg.types.Attribute] 
(through reference chain: com.abc.xyz.da.kg.services.models.RelationshipBean2["entities"])' 

RelationshipBean2 class

public class RelationshipBean2 {
     private ArrayList<Entity> entities;
     private String searchFilterQuery;
     private int resultCount;
     private Map<StructuralFeature, List<Object>> documentAttributeValues;
   // getters and setters

Reference Chain - Entity is an interface which extends from another inferace Element. In a class that implements Element I have the following Map. I have written a Mixin class for Element with the following annotations.

protected Map<Attribute, Object> attributeValues = new HashMap<Attribute, Object>();

This map is the source of exception:-

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")

public abstract class ElementMixin implements Element {

@JsonDeserialize(keyUsing = AttributeKeyDeserializer.class)
protected Map<Attribute, Object> attributeValues = new HashMap<Attribute, Object>();
}

I have implemented the key deserializer and registered it with ObjectMapper using SimpleModule.

My deserializer:-

public class AttributeKeyDeserializer extends KeyDeserializer {

public AttributeKeyDeserializer() {
    super();
}


@Override
public Object deserializeKey(String content, DeserializationContext context)
            throws IOException, JsonProcessingException {
   // ObjectMapper mapper = (ObjectMapper) context.getParser().getCodec();
   // Attribute attribute = mapper.readValue(content, Attribute.class);
   // return attribute.getID();
   return "Attr";
}

ObjectMapper config and deserializer registeration:-

final ObjectMapper mapper = new ObjectMapper();

MixinModule mixinModule = new MixinModule("KGMixinModule", new Version(1,
            0, 0, "SNAPSHOT"));
StructuralFeatureDeserializer structuralFeatureDeserializer = new StructuralFeatureDeserializer();
mixinModule.addDeserializer(StructuralFeature.class,
            structuralFeatureDeserializer);
mixinModule.addKeyDeserializer(StructuralFeature.class,
            new StructuralFeatureKeyDeserializer());
mixinModule.addKeyDeserializer(Attribute.class,
            new AttributeKeyDeserializer());
mapper.registerModule(mixinModule);

AnnotationIntrospector primary = new JaxbAnnotationIntrospector();
AnnotationIntrospector secondary = new JacksonAnnotationIntrospector();
AnnotationIntrospector pair = new AnnotationIntrospector.Pair(primary,
            secondary);
mapper.setAnnotationIntrospector(pair);

// Set up the provider
JacksonJaxbJsonProvider jaxbProvider = new JacksonJaxbJsonProvider();
jaxbProvider.setMapper(mapper);

Here MixinModule extends from Jackson's SimpleModule

Could someone please point out what it is that I am missing, why is the deserializer not being called. I have been struggling a lot with this.

Some more context: I am trying to write REST api on top of the API that I do not own, so modifying those classes is out of scope. I can only use Jackson v1.9.13

Any help would be greatly appreciated.


Solution

  • I finally found what was going wrong. I had added the annotated Map field in a Super class mixin while the field was actually present in one of the sub class. I assumed that Mixin class would add that field in the Super class.

    At the end, I created a Mixin class for that sub class and added the annotated field there and it all worked.