3

In my company we have a fixed JSON message structure:

{
    "headerVal1": ""
    "headerVal2": ""
    "customPayload": {
        "payloadType":""
    }
}

I would like to have some kind of library, which allows me, to not care for the company defined message structure, and instead just send and receive the payload.

My idea was, to define the structure of the company template as one object, and use subtypes of a PayloadObject.

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.MINIMAL_CLASS,
    property = "payloadType",
    visible = false)
public abstract class PayloadObject {
}

Now I can create subclasses of the PayloadObject, and it can be automatically deserialized in this structure, as long as the property payloadType has a string ".SubTypeName".

This is problematic, since I cannot customize it, not even remove the superflous . in the beginning. This is unfortunately not necessarily compatible with other, existing systems in the company, we need to interface with.

The alternative is, to add a @JsonSubTypes-annotation in which I can add all the possible subtypes - which I don't want to know when writing the library. So this option won't work for me.

I thought, it might help to have the @JsonType-annoation with the subtypes, but I still have to add the @JsonSubTypes, which does not help.


Is there a way, to add subtypes to a basetype without modifying the basetypes java-file?


If this helps: We are working with Java Spring.

  • Hmm you could try using a [mixin](https://github.com/FasterXML/jackson-docs/wiki/JacksonMixInAnnotations) to define the subtypes. That way you could provide the subtype definitions from the caller side and with some preprocessing etc. it should even be possible to have those mixins automatically generated. – Thomas Apr 29 '19 at 08:54
  • The only thing I learned so far about mix-ins is, how to use them to ignore certain properties, as described here: https://www.baeldung.com/jackson-annotations - but I don't know how to use them for - more or less - the opposite. – derM - not here for BOT dreams Apr 29 '19 at 10:24
  • Well, you can use mixins to override/add a lot of annotations/configuration. There might be limitations tough - we're using them to some extend but not yet to add/set subtypes. – Thomas Apr 29 '19 at 10:30
  • If you are looking for `MixIn` examples, check: [Jackson serialization of abstract interface](https://stackoverflow.com/questions/54224705/jackson-serialization-of-abstract-interface), [Dynamic addition of fasterxml Annotation?](https://stackoverflow.com/questions/25290915/dynamic-addition-of-fasterxml-annotation), [Custom Jackson Serializer for a specific type in a particular class](https://stackoverflow.com/questions/23252918/custom-jackson-serializer-for-a-specific-type-in-a-particular-class). – Michał Ziober Apr 29 '19 at 13:03

1 Answers1

3

ObjectMapper has a method registerSubtypes(NamedType) which can be used to add subtypes for use, without having them in the annotations.

For this I created a new Annotation (I might have reused @JsonTypeName, but it might be abusive)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyJsonSubtype
{
   public String jsonTypeName();
}

Then I wrote me a method

public static void registerMyJsonSubtypes(ObjectMapper om, Object... reflectionArgs) {
    Reflections reflections = new Reflections(reflectionArgs);
    Set<Class<?>> types = reflections.getTypesAnnotatedWith(MyJsonSubtype.class);
    for (Class type : types) {
        String name = ((MyJsonSubtype) type.getAnnotation(MyJsonSubtype.class)).jsonTypeName();
        om.registerSubtypes(new NamedType(type, name));
    }
}

which uses Reflections to get all annotated types declared inside searched packages and registers them as subtypes for the ObjectMapper.

This still requires the @JsonTypeInfo-annotation on the base class to mark the object as potentially extensible, so the mapper knows, which property to use, to resolve the name, but I figure, this is is providable. My main attention was on the problem, that I don't want to declare all future subtypes in an annotation on the base class.

I am a Java beginner though, so please share your thoughts, if this is unnecessary or could/should/must be improved.