3

I have a big set of classes (like more that 100) and they are all extend from some abstract class, let's call it ParentClass. Let's call child classes ChildA,ChildB, etc. How can I register custom deserializer for all children and get class type inside my Deserializer? I tried:

module.addDeserializer(ParentClass.class, new MyObjectDeserializer());

but it does not work.

I want to skip doing (what is working):

module.addDeserializer(ChildA.class, new MyObjectDeserializer(ChildA.class));
module.addDeserializer(ChildB.class, new MyObjectDeserializer(ChildB.class));
module.addDeserializer(ChildC.class, new MyObjectDeserializer(ChildC.class));
//etc......

Class type should be known, as I am use Jackson for spring @RequestBody method, what have defined class name there. Any ideas how this can be done?

Tom
  • 363
  • 7
  • 17
  • If you're using the same parent deserializer, is there a need to register all those child classes? Maybe you should just define your controller functions to receive the Parent class and distinguish between the child classes some other way. – hofan41 Jan 14 '15 at 17:43
  • That's not a good solution. It's much easy to deal with direct classes, rather that create a mechanism to distinguish them from abstract. (Plus, we have a lot of code in concrete classes). – Tom Jan 14 '15 at 17:54
  • I consider this a bug in Jackson. I’ve filed an issue: https://github.com/FasterXML/jackson-databind/issues/1784 – Benedikt Waldvogel Oct 03 '17 at 18:58

2 Answers2

1

As far as I know, I don't think there is a mechanism in jackson that will address your exact needs.

However, there are a couple alternatives you can try. Deserializing polymorphic types with Jackson describes one such alternative, however, you would still need to explicitly define all of the supported subtypes.

Another alternative that would not require you to explicitly define deserialization relationships would be to change your class hierarchy from one of inheritance to that of a container.

For example, converting your abstract parent class to a container like so:

public class DataContainer<T> {
  String commonString;
  Integer commonInteger;  

  T subData;
}

Would allow you to simply define in your controller input function as

public String controllerFunction(DataContainer<ClassA> classA);

without a need to define all these subclass deserializations.

Community
  • 1
  • 1
hofan41
  • 1,438
  • 1
  • 11
  • 25
0

Late to the party but I had a similar problem which I solved by registering a custom Deserializers to my SimpleModule. The code is in Kotlin but it should be easy to port it to Java.

The class itself:

class UseBaseClassSimpleDeserializers(
    private val baseClass: Class<*>,
    private val baseClassDeserializer: JsonDeserializer<*>
) : SimpleDeserializers() {
    @Throws(JsonMappingException::class)
    override fun findBeanDeserializer(
        type: JavaType?,
        config: DeserializationConfig?,
        beanDesc: BeanDescription?
    ): JsonDeserializer<*>? {
        val beanDeserializer = super.findBeanDeserializer(type, config, beanDesc)
        return if (beanDeserializer == null && baseClass.isAssignableFrom(type!!.rawClass)) {
            baseClassDeserializer
        } else {
            beanDeserializer
        }
    }
}

How to register the custom Deserializers class to a SimpleModule:

val simpleModule = SimpleModule()
simpleModule.setDeserializers(UseBaseClassSimpleDeserializers(ParentClass::class.java, ParentClassDeserializer()))
Campi
  • 1,932
  • 1
  • 16
  • 21