With some help from this answer and based on the Spring Boot Example
Here is a DTO1 and DTO2 class which look the same (getters and setters not shown) :
public class DTO1 {
private String property1;
private String property2;
private String property3;
Here is a controller for testing:
@RestController
public class HelloController {
@RequestMapping("/dto1")
public ResponseEntity<DTO1> dto1() {
return new ResponseEntity<DTO1>(new DTO1("prop1", "prop2", "prop3"), HttpStatus.OK);
}
@RequestMapping("/dto2")
public ResponseEntity<DTO2> dto2() {
return new ResponseEntity<DTO2>(new DTO2("prop1", "prop2", "prop3"), HttpStatus.OK);
}
}
Here is my WebConfig
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
@Bean
public MappingJackson2HttpMessageConverter customJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
MyBeanSerializerFactory customSerializationFactory = new MyBeanSerializerFactory(new SerializerFactoryConfig());
customSerializationFactory.getClasses().add(DTO1.class);
customSerializationFactory.getFieldsToIgnore().add("property2");
objectMapper.setSerializerFactory(customSerializationFactory);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(customJackson2HttpMessageConverter());
}
}
Here is the custom BeanserializerFactory:
public class MyBeanSerializerFactory extends BeanSerializerFactory {
private Set<Class> classes = new HashSet<>();
private Set<String> fieldsToIgnore = new HashSet<>();
protected MyBeanSerializerFactory(SerializerFactoryConfig config) {
super(config);
// TODO Auto-generated constructor stub
}
public Set<Class> getClasses() {
return classes;
}
public Set<String> getFieldsToIgnore() {
return fieldsToIgnore;
}
@Override
protected void processViews(SerializationConfig config, BeanSerializerBuilder builder) {
super.processViews(config, builder);
// ignore fields only for concrete class
// note, that you can avoid or change this check
if (classes.contains(builder.getBeanDescription().getBeanClass())) {
// get original writer
List<BeanPropertyWriter> originalWriters = builder.getProperties();
// create actual writers
List<BeanPropertyWriter> writers = new ArrayList<BeanPropertyWriter>();
for (BeanPropertyWriter writer : originalWriters) {
String propName = writer.getName();
// if it isn't ignored field, add to actual writers list
if (!fieldsToIgnore.contains(propName)) {
writers.add(writer);
}
}
builder.setProperties(writers);
}
}
}
Here is a test which shows property2 removed from DTO1, but not DTO2 :
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void test1() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/dto1").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(content().string(equalTo("{\"property1\":\"prop1\",\"property3\":\"prop3\"}")));
mvc.perform(MockMvcRequestBuilders.get("/dto2").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(content()
.string(equalTo("{\"property1\":\"prop1\",\"property2\":\"prop2\",\"property3\":\"prop3\"}")));
}
}
See https://github.com/gregclinker/json-mapper-example for code above.