jackson-databind: Failed to specialize `Map` type during serialization where type key type incompatibility overidden via "raw" types

I’m using a class with a Map attribute, whose value is a Collection. I’m using OrientDB, so when I obtain this object from database, it’s returning a OTrackedMap object.

When I’m trying to serialize it, it works perfect until Jackson v2.9.2. If I upgrade it to v2.9.3 or v2.9.4, it crashes with the following exception:

INFO: Jackson version: 2.9.4

com.fasterxml.jackson.databind.JsonMappingException: Failed to specialize base type java.util.Map<java.lang.String,java.util.Collection<java.lang.String>> as com.orientechnologies.orient.core.db.record.OTrackedMap, problem: Type parameter #1/2 differs; can not specialize java.lang.String with java.lang.Object (through reference chain: com.example.jackson.AccessModel["repositoryPrivileges"])

	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:391)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:351)
	at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:316)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:727)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
	at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3893)
	at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3207)
	at com.example.jackson.JacksonTest.testSerialization(JacksonTest.java:37)
	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)
	[...]

You can take a look at this gist to see an example.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 16 (8 by maintainers)

Commits related to this issue

Most upvoted comments

I didn’t want to create new issue, but I’m also having same exception when serializing or deserializing classes with nested generic types. Here is a simple project with reduced example model and test to verify presence of problem. Difference is that it affects versions 2.8.11 up to current latest 2.9.4, but works OK for versions <=2.8.10

Quick note: realized that use of “static typing” can be used to work around the problem, because that will force use of declared type over attempting to combine declared (static) type with runtime instance type. Although you may or may not want to force it globally (MapperFeature.USE_STATIC_TYPING), it is possible to force it on specific property:

// works on getter or field:
@JsonSerialize(typing = JsonSerialize.Typing.STATIC)
public Map<String, Collection<String>> getRepositoryPrivileges() { ... }

and this will prevent the problem here. So it may be worth considering this as short-term fix; if this is actual type for real use case it should be safe for serialization.

I will still pursue potential change I outlined above, but thought work-around would be useful.

As far as I can see, the problem seems to be in TypeFactory#_verifyAndResolvePlaceholders in line 460. There is checked, if the two raw classes are equal. In this example this would be Object and String. In my opinion instanceof or isAssignableFrom should be used instead.

I’ve updated the gist with a working example. Like you said, the problem had to do with Map key type declaration. If the key is changed from String to Object, it works. I guess that it’s related to the Map implementation, which extends from LinkedHashMap<Object, T>.