Issue
I have an entity with multiple @ManyToOne
associations. I am using spring-boot to expose a REST API. Currently, I have multiple REST API's which return a JSON response of the whole entity, including associations.
But I don't want to serialize all associated objects in all REST APIs.
For example
- API-1 should return parent + associationA object
- API-2 should return parent + associationA + associationB object
- API-3 should return parent + associationB + associationC + associationD
So, in my serialization process, I want to ignore all association except associationA for API-1.
For API-2 I want to ignore other associations except A and B
How do I dynamically ignore these properties during Jackson serialization?
Notes: I'm using the same class for each; I am not interested in creating a DTO for each API.
Any suggestions are kingly appreciated.
Solution
I've put together three approaches for performing dynamic filtering in Jackson. One of them must suit your needs.
Using @JsonView
You could use @JsonView
:
public class Views {
interface Simple { }
interface Detailed extends Simple { }
}
public class Foo {
@JsonView(Views.Simple.class)
private String name;
@JsonView(Views.Detailed.class)
private String details;
// Getters and setters
}
@RequestMapping("/foo")
@JsonView(Views.Detailed.class)
public Foo getFoo() {
Foo foo = new Foo();
return foo;
}
Alternatively you can set the view dynamically with MappingJacksonValue
.
@RequestMapping("/foo")
public MappingJacksonValue getFoo() {
Foo foo = new Foo();
MappingJacksonValue result = new MappingJacksonValue(foo);
result.setSerializationView(Views.Detailed.class);
return result;
}
Using a BeanSerializerModifier
You could extend BeanSerializerModifier
and then override the changeProperties()
method. It allows you to add, remove or replace any of properties for serialization, according to your needs:
public class CustomSerializerModifier extends BeanSerializerModifier {
@Override
public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
// In this method you can add, remove or replace any of passed properties
return beanProperties;
}
}
Then register the serializer as a module in your ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new CustomSerializerModifier());
}
});
Using @JsonFilter
with a SimpleBeanPropertyFilter
Another approach involves @JsonFilter
:
@JsonFilter("customPropertyFilter")
public class Foo {
private String name;
private String details;
// Getters and setters
}
Extend SimpleBeanPropertyFilter
and override the serializeAsField()
method according to your needs:
public class CustomPropertyFilter extends SimpleBeanPropertyFilter {
@Override
public void serializeAsField(Object pojo, JsonGenerator jgen,
SerializerProvider provider,
PropertyWriter writer) throws Exception {
// Serialize a field
// writer.serializeAsField(pojo, jgen, provider, writer);
// Omit a field from serialization
// writer.serializeAsOmittedField(pojo, jgen, provider);
}
}
Then register the filter in your ObjectMapper
:
FilterProvider filterProvider = new SimpleFilterProvider()
.addFilter("customPropertyFilter", new CustomPropertyFilter());
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(filterProvider);
If you want to make your filter "global", that is, to be applied to all beans, you can create a mix-in class and annotate it with @JsonFilter("customPropertyFilter")
:
@JsonFilter("customPropertyFilter")
public class CustomPropertyFilterMixIn {
}
Then bind the mix-in class to Object
:
mapper.addMixIn(Object.class, CustomPropertyFilterMixIn.class);
Answered By - cassiomolin
Answer Checked By - David Marino (JavaFixing Volunteer)