My supertype is annotated with
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "_typeid")
-so that serialised subtypes include the extra field _typeid
containing the name of the subtype. This is intentional and necessary for my app.
But in a particular context I would like to export them as "pure" JSON
, i.e. without the _typeid
metadata field.
Is there any way of making an ObjectMapper
ignore the @JsonTypeinfo
annotation during serialisation? I can't find any relevant config- or feature settings. Would I have to resort to postfiltering or alternative serialisers?
I know that removing or altering the annotations would do it, but this is not an option in this case.
ObjectMapper().configure(MapperFeature.USE_ANNOTATIONS, false);
-will turn off all annotations. This does remove the offending field, but also kills other annotations that I would like to work.
If there are fields in Java objects that do not wish to be serialized, we can use the @JsonIgnore annotation in the Jackson library. The @JsonIgnore can be used at the field level, for ignoring fields during the serialization and deserialization.
Note that Jackson does not use java. io. Serializable for anything: there is no real value for adding that. It gets ignored.
Jackson is a solid and mature JSON serialization/deserialization library for Java. The ObjectMapper API provides a straightforward way to parse and generate JSON response objects with a lot of flexibility.
The @JsonIgnore annotation marks a field of a POJO to be ignored by Jackson during serialization and deserialization. Jackson ignores the field both JSON serialization and deserialization. An example of Java class that uses the @JsonIgnore annotation is this.
You can add/remove annotation in runtime using JsonView
annotation. Let's assume that we have one abstract class Base
and one implementation Base1
. Instead of adding annotations to Base
directly we can do that by adding new interface with these annotations. See below example:
abstract class Base {
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "_typeid")
@JsonSubTypes({
@JsonSubTypes.Type(name = "base1", value = Base1.class)
})
interface BaseTypeView {
}
class Base1 extends Base {
private String value = "Base 1";
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Now, we need to create two ObjectMapper
s: one wich uses this view and another which does not.
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class JsonApp {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = createObjectMapper();
ObjectMapper mapperWithView = createObjectMapper();
mapperWithView.addMixIn(Base.class, BaseTypeView.class);
System.out.println(mapper.writeValueAsString(new Base1()));
System.out.println(mapperWithView.writeValueAsString(new Base1()));
}
private static ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
return mapper;
}
}
Above code prints:
{
"value" : "Base 1"
}
{
"_typeid" : "base1",
"value" : "Base 1"
}
Based on Michal's answer, this simplified version is pretty close to what I'm looking for:
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@JsonSubTypes.Type(value = Cat.class)
})
class Animal { }
class Cat extends Animal {
public final String genus = "felis";
}
public class Example {
public static void main(String[] args) throws Exception {
Cat bill = new Cat();
ObjectMapper typed = new ObjectMapper();
System.out.println(typed.writeValueAsString(bill));
@JsonTypeInfo(use = JsonTypeInfo.Id.NONE)
class NoTypes { }
ObjectMapper untyped = new ObjectMapper().addMixIn(Animal.class, NoTypes.class);
System.out.println(untyped.writeValueAsString(bill));
}
}
This will output
{"@type":"Cat","genus":"felis"}
{"genus":"felis"}
This approach has the advantages that it requires no control over the data classes - everything can be done locally while configuring the mapper - and that the mixin is general and can be applied to any base class.
It does still require explicit configuration for every targeted base class, though, so it is not quite a general solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With