How to serialize declarative links (jersey) with jackson - java

I am using declarative linking in my project. My jackson mapper configuration is
final ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
mapper.configure(MapperFeature.AUTO_DETECT_FIELDS, false);
mapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_GETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_SETTERS, false);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
As I have disabled any kind of auto detection, injected links like
#InjectLinks({
#InjectLink(rel = "bookmark", resource = ConnectionsResource.class, style = Style.ABSOLUTE_PATH) })
#JsonProperty("links")
Link[] links;
are serialized to an empty JSON object (because none of the fields in "Link" is annotated with #JsonProperty).
How to enable serialization for Links only for the fields rel and href without changing my global mapper configuration?

So one way to make this work is to use a customer serializer. You would have to add a new module for this serializer to the ObjectMapper, but this should not effect the rest of the configurations.
Here's the serializer
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import javax.ws.rs.core.Link;
public class LinkSerializer extends JsonSerializer<Link>{
#Override
public void serialize(Link link, JsonGenerator jg, SerializerProvider sp)
throws IOException, JsonProcessingException {
jg.writeStartObject();
jg.writeStringField("rel", link.getRel());
jg.writeStringField("href", link.getUri().toString());
jg.writeEndObject();
}
}
Here a test class
public class TestClass {
#JsonProperty("links")
protected List<Link> links;
protected String name;
protected String id;
// getter and setters
}
And the test run
public static void main(String[] args) throws Exception{
ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);
mapper.configure(MapperFeature.AUTO_DETECT_FIELDS, false);
mapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_GETTERS, false);
mapper.configure(MapperFeature.AUTO_DETECT_SETTERS, false);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(Link.class, new LinkSerializer());
mapper.registerModule(simpleModule);
Link link1 = Link.fromUri(URI.create("http://localhost:8080/")).rel("one").build();
Link link2 = Link.fromUri(URI.create("http://localhost:8080/")).rel("two").build();
TestClass test = new TestClass();
test.getLinks().add(link1);
test.getLinks().add(link2);
String json = mapper.writeValueAsString(test);
System.out.println(json);
}
produces this result
{
"links" : [ {
"rel" : "one",
"href" : "http://localhost:8080/"
}, {
"rel" : "two",
"href" : "http://localhost:8080/"
} ]
}
Hope this helps.

Here is an example of using the Jackson mixin annotation for serializing and deserializing the Link object including all the properties:
#JsonAutoDetect(
fieldVisibility = JsonAutoDetect.Visibility.NONE,
getterVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
#JsonDeserialize(using = LinkMixin.LinkDeserializer.class)
public abstract class LinkMixin extends Link {
private static final String HREF = "href";
#JsonProperty(HREF)
#Override
public abstract URI getUri();
#JsonAnyGetter
public abstract Map<String, String> getParams();
public static class LinkDeserializer extends JsonDeserializer<Link> {
#Override
public Link deserialize(
final JsonParser p,
final DeserializationContext ctxt) throws IOException {
final Map<String, String> params = p.readValueAs(
new TypeReference<Map<String, String>>() {});
if (params == null) {
return null;
}
final String uri = params.remove(HREF);
if (uri == null) {
return null;
}
final Builder builder = Link.fromUri(uri);
params.forEach(builder::param);
return builder.build();
}
}
}

Related

Custom Jackson serializer never gets triggered for one object but it gets for another

I have a very strange situation.
I have a custom Jackson serializer for Object class inside my Jakarta EE/Sprin Data JPA app which is registered trough ObjectMapper inside ContextResolver implementation.
I have my REST endpoint which looks like this:
#GET
#Produces(MediaType.APPLICATION_JSON)
#Roles({"user", "operator", "admin"})
public Response fetchAll(#Context SecurityContext securityContext) {
return ResponseUtils.createSuccessResponse(facade.findAllPrimary());
}
createSuccessResponse method returns a type Response which looks like this:
public class Response {
private String message;
private int code;
private Object data;
}
and sets the value of facade.findAllPrimary() which returns a List to its data field.
So, the response JSON looks like this:
{
"message": "ok",
"code": 0,
"data": [
{
"id": null,
"uniqueId": "481333a7-5101-4bbd-9997-34c0e58160cd",
"title": "",
"text": null,
"hidden": true,
"dateOfSubmission": null,
"likes": 0,
"dislikes": 0,
"comments": null,
"commentsIds": null
},
{
"id": null,
"uniqueId": "2279f268-042c-42cd-8d5d-44edfc818d9b",
"title": "",
"text": null,
"hidden": true,
"dateOfSubmission": null,
"likes": 0,
"dislikes": 0,
"comments": null,
"commentsIds": null
}
]
}
My custom serializer looks like this:
public class RootEntitySerializer extends JsonSerializer<Object> {
.
.
.
#Override
public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
.
.
.
}
When I call the REST endpoint to trigger the serialization, and I put the debugger at the first line of the serialize method, I see that it's triggered just for the BlogPost objects, but not for the Response object.
Why?
EDIT: Here's the code of my ContextResolver:
package org.example.config;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Application;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.ext.ContextResolver;
import jakarta.ws.rs.ext.Provider;
import org.example.model.RootEntity;
import org.example.utils.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.SimpleDateFormat;
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class JacksonDatatypeJacksonProducer implements ContextResolver<ObjectMapper> {
#Context
private Application application;
private static Logger LOG = LoggerFactory.getLogger(JacksonDatatypeJacksonProducer.class);
private final ObjectMapper objectMapper;
private static CustomBeanSerializerModifier customBeanSerializerModifier;
private static CustomBeanDeserializerModifier customBeanDeserializerModifier;
public JacksonDatatypeJacksonProducer() {
SecurityContext securityContext = null;
if (application != null) {
securityContext = ((SecurityContext)application.getProperties().get("securityContext"));
}
this.objectMapper = createDefaultMapper(securityContext);
}
#Override
public ObjectMapper getContext(Class<?> type) {
SecurityContext securityContext = ((SecurityContext)application.getProperties().get("securityContext"));
customBeanSerializerModifier.setSecurityContext(securityContext);
customBeanDeserializerModifier.setSecurityContext(securityContext);
SimpleModule module = new SimpleModule();
module.setSerializerModifier(customBeanSerializerModifier);
module.setDeserializerModifier(customBeanDeserializerModifier);
objectMapper.registerModule(module);
return objectMapper;
}
private static ObjectMapper createDefaultMapper(SecurityContext securityContext) {
LOG.warn("CREATING OBJECT MAPPER");
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); // enable writing dates as strings
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS")); // set custom date format
SimpleModule module = new SimpleModule();
customBeanSerializerModifier = new CustomBeanSerializerModifier();
customBeanDeserializerModifier = new CustomBeanDeserializerModifier();
module.setSerializerModifier(customBeanSerializerModifier);
module.setDeserializerModifier(customBeanDeserializerModifier);
mapper.registerModule(module);
return mapper;
}
private static class CustomBeanSerializerModifier extends BeanSerializerModifier {
SecurityContext securityContext = null;
#Override
public JsonSerializer<?> modifySerializer(com.fasterxml.jackson.databind.SerializationConfig config, com.fasterxml.jackson.databind.BeanDescription beanDesc, JsonSerializer<?> serializer) {
if (RootEntity.class.isAssignableFrom(beanDesc.getBeanClass()) || beanDesc.getBeanClass().equals(Response.class)) {
return new RootEntitySerializer((JsonSerializer<Object>) serializer, this.securityContext);
}
return serializer;
}
public void setSecurityContext(SecurityContext securityContext) {
this.securityContext = securityContext;
}
}
private static class CustomBeanDeserializerModifier extends BeanDeserializerModifier {
SecurityContext securityContext = null;
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return new RootEntityDeserializer(beanDesc.getBeanClass(), securityContext);
}
public void setSecurityContext(SecurityContext securityContext) {
this.securityContext = securityContext;
}
}
}

How to restrict jackson from parsing millis to LocalDate in json request

I need to validate LocalDate fields in json requests. What i want is to prevent deserializing numbers as miilis to LocalDate. Here is example:
I have an entity:
public class Test {
#NotNull
#JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate birthDate;
//getter and setter of course
}
Jackson2ObjectMapperBuilder config:
#Bean
public Jackson2ObjectMapperBuilder objectMapperBuilder() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
builder.featuresToEnable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
builder.modulesToInstall(new JavaTimeModule());
return builder;
}
Now if i'm receiveing:
{
"birthDate": 1
}
the result is birthDate=1970-01-02
I'm able to do so by setting leniency to false:
objectMapper.configOverride(LocalDate.class).setFormat(JsonFormat.Value.forLeniency(false));
objectMapper.configOverride(LocalDateTime.class).setFormat(JsonFormat.Value.forLeniency(false));
And then it's working by throwing MismatchedInputException
But it's a little brutal to backward compatibility of our service, because we need to change all our date patterns from "yyyy-MM-dd" to "uuuu-MM-dd" and i wonder is there some solution to say jackson "If you see numbers or anything different from the pattern while deserialization, throw an exception"
You could write a custom LocalDateDeserializer:
public class MyLocalDateDeserializer extends JsonDeserializer<LocalDate> implements ContextualDeserializer {
private LocalDateDeserializer defaultDeserializer = new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
public MyLocalDateDeserializer() {
super();
}
public MyLocalDateDeserializer(LocalDateDeserializer defaultDeserializer) {
super();
this.defaultDeserializer = defaultDeserializer;
}
#Override
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException
{
if (StringUtils.isNumeric(parser.getText())) {
throw JsonMappingException.from(parser, "Not a String representation of Date ");
}
return defaultDeserializer.deserialize(parser, context);
}
#Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
BeanProperty property) throws JsonMappingException
{
JsonFormat.Value format = findFormatOverrides(ctxt, property, handledType());
return (format == null) ? this : new MyLocalDateDeserializer(new LocalDateDeserializer(DateTimeFormatter.ofPattern(format.getPattern())));
}
protected JsonFormat.Value findFormatOverrides(DeserializationContext ctxt,
BeanProperty prop, Class<?> typeForDefaults)
{
if (prop != null) {
return prop.findPropertyFormat(ctxt.getConfig(), typeForDefaults);
}
// even without property or AnnotationIntrospector, may have type-specific defaults
return ctxt.getDefaultPropertyFormat(typeForDefaults);
}
}
and register it when needed.
Here my simple Tests:
#Test()
public void testObjectMapperForLocalDate() throws IOException {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDate.class, new MyLocalDateDeserializer());
builder.modulesToInstall(javaTimeModule);
ObjectMapper objectMapper = builder.build();
DateContainer container = objectMapper.readValue("{\r\n" +
" \"birthDate\": \"1999-01-01\"\r\n" +
"}", DateContainer.class);
System.out.println(container.getBirthDate());
}
#Test()
public void testFailObjectMapperForLocalDate() throws IOException {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDate.class, new MyLocalDateDeserializer());
builder.modulesToInstall(javaTimeModule);
ObjectMapper objectMapper = builder.build();
assertThrows(JsonMappingException.class, () -> {
DateContainer container = objectMapper.readValue("{\r\n" +
" \"birthDate\": 1\r\n" +
"}", DateContainer.class);
System.out.println(container.getBirthDate());
});
}
EDIT
Deserializer uses Pattern

How to serialize List within object without annotation?

I have JSON that looks something like this (the full JSON is much larger):
{
"legalLastName": "lastName",
"legalFirstName": "firstName",
"terminationDate": null,
"collegeEducation": [{
"major": "Finance",
"school": "Towson University",
"quarter": null,
"degreeType": "B.S.",
"yearEarned": "1990",
"degreeLevel": "Undergraduate"
}]
}
How do I use the ObjectMapper to apply custom serialization to collegeEducation? I can't use the annotation JsonSerializer, because the POJO is generated, and that library doesn't provide a way to apply that annotation. So I'd like to use the default ObjectMapper serialization for all fields but the list.
Objective: A field in Education named as degreeType will be serialized to json field degree
Mixin or Custom serializer can be used
Student and Education class
Lets define the Student and Education class as follows
static class Education {
String major;
String degreeType;
}
static class Student {
String legalLastName;
String legalFirstName;
List<Education> educationList;
}
Mixin
Use mixin to define a parallel class with updated field specifications
Mixin class for Education
Define the field in the actual object String degreeType;
Add the custom field name to be serialized to #JsonProperty("degree")
abstract class EducationMixin {
#JsonProperty("degree")
String degreeType;
}
Configure ObjectMapper with Mixin
Enable field visibility(as the class does not have getter/setter)
Register the education mixin
static void withMixin(Student student) throws Exception {
ObjectMapper studentMapper = new ObjectMapper();
studentMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
studentMapper = studentMapper.addMixIn(Education.class, EducationMixin.class);
System.out.println(studentMapper.writeValueAsString(student));
}
Or Custom Serializer
Custom serializer's can be used to serialize java objects.
Add custom serializer for Education
Add the custom serializer class to Serialize Education
static class EducationSerializer extends JsonSerializer<Education> {
#Override
public void serialize(Education education, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("major", education.major);
gen.writeStringField("degree", education.degreeType);
gen.writeEndObject();
}
}
Initialize ObjectMapper with necessary configuration
Enable field visibility(as the class does not have getter/setter)
Register the education serializer
static void withCustom(Student student) throws Exception {
ObjectMapper studentMapper = new ObjectMapper();
studentMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
SimpleModule studentModule = new SimpleModule();
studentModule.addSerializer(Education.class, new EducationSerializer());
studentMapper.registerModule(studentModule);
System.out.println(studentMapper.writeValueAsString(student));
}
Full working code
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MixinTest {
public static void main(String[] args) throws Exception {
Student student = new Student();
student.legalFirstName = "first";
student.legalLastName = "last";
Education education = new Education();
education.degreeType = "degreetypevalue";
education.major = "majorvalue";
student.educationList = new ArrayList<>();
student.educationList.add(education);
withMixin(student);
withCustom(student);
}
static void withMixin(Student student) throws Exception {
ObjectMapper studentMapper = new ObjectMapper();
studentMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
studentMapper = studentMapper.addMixIn(Education.class, EducationMixin.class);
System.out.println(studentMapper.writeValueAsString(student));
}
static void withCustom(Student student) throws Exception {
ObjectMapper studentMapper = new ObjectMapper();
studentMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
SimpleModule studentModule = new SimpleModule();
studentModule.addSerializer(Education.class, new EducationSerializer());
studentMapper.registerModule(studentModule);
System.out.println(studentMapper.writeValueAsString(student));
}
static class Education {
String major;
String degreeType;
}
static class Student {
String legalLastName;
String legalFirstName;
List<Education> educationList;
}
abstract class EducationMixin {
#JsonProperty("degree")
String degreeType;
}
static class EducationSerializer extends JsonSerializer<Education> {
#Override
public void serialize(Education education, JsonGenerator gen, SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("major", education.major);
gen.writeStringField("degree", education.degreeType);
gen.writeEndObject();
}
}
}

Jackon custom deserializer never called

This is the attribute on which I have used the #JsonDeserialize
#Transient
#JsonDeserialize(using = SharedUserDeserializer.class)
private Set<UserVehicleMappingVO> sharedVehicle;
public Set<UserVehicleMappingVO> getSharedVehicle() {
return sharedVehicle;
}
public void setSharedVehicle(Set<UserVehicleMappingVO> sharedVehicle) {
this.sharedVehicle = sharedVehicle;
}
And the custom Deserializer code is
public class SharedUserDeserializer extends JsonDeserializer<Set<UserVehicleMappingVO>> {
#Override
public Set<UserVehicleMappingVO> deserialize(JsonParser paramJsonParser,
DeserializationContext paramDeserializationContext)
throws IOException, JsonProcessingException {
try {
Set<UserVehicleMappingVO> list = new ObjectMapper().readValue(paramJsonParser.toString(),
new TypeReference<Set<UserVehicleMappingVO>>() {});
return list;
} catch (IOException e) {
e.printStackTrace();
}
return new HashSet<>();
}
}
But the deserializer is never called. Please help
Everytime I get this exception instead....
ERROR :::9,gajendranc#azuga.com - Exception in
method===org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'trackee' on field 'sharedVehicle': rejected value
[[{"userId":"5d48b74f-7da2-11e7-87bf-
1383429d1d89","expireTime":1504190100000}]]; codes
[typeMismatch.trackee.sharedVehicle,typeMismatch.sharedVehicle,
typeMismatch.java.util.Set,typeMismatch]; arguments
[org.springframework.context.support.DefaultMessageSourceResolvable: codes
[trackee.sharedVehicle,sharedVehicle]; arguments []; default message
[sharedVehicle]]; default message [Failed to convert property value of type
[java.lang.String] to required type [java.util.Set] for property
'sharedVehicle'; nested exception is java.lang.IllegalStateException: Cannot
convert value of type [java.lang.String] to required type
[com.azuga.user.manager.UserVehicleMappingVO] for property
'sharedVehicle[0]':
Please help........
Have you register the module as mentioned in this example http://www.baeldung.com/jackson-deserialization ?
ObjectMapper mapper=new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Set.class, new SharedUserDeserializer());
mapper.registerModule(module);
It is working for me :
#Test
public void test() throws IOException {
ObjectMapper mapper=new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Set.class, new SharedUserDeserializer());
mapper.registerModule(module);
TestUser user=new TestUser();
Set<UserVehicleMappingVO> sets=new HashSet<>();
sets.add(new UserVehicleMappingVO("test1"));
user.setVechicles(sets);
String jsonString=mapper.writeValueAsString(user);
Set<UserVehicleMappingVO> vechiles=mapper.readValue(jsonString, new TypeReference<Set<UserVehicleMappingVO>>() {
});
}
Model :
public class TestUser {
#JsonDeserialize(using = SharedUserDeserializer.class)
private Set<UserVehicleMappingVO> vechicles;
//getters and setters
}
public class UserVehicleMappingVO {
private String name;
//getters and setters
}
Custom Deserializer class :
public class SharedUserDeserializer extends JsonDeserializer<Set<UserVehicleMappingVO>> {
#Override
public Set<UserVehicleMappingVO> deserialize(JsonParser paramJsonParser,
DeserializationContext paramDeserializationContext)
throws IOException, JsonProcessingException {
try {
System.out.println("hello");
Set<UserVehicleMappingVO> list = new ObjectMapper().readValue(paramJsonParser.toString(),
new TypeReference<Set<UserVehicleMappingVO>>() {});
return list;
} catch (IOException e) {
e.printStackTrace();
}
return new HashSet<>();
}
Response :
Output {"vechicles":[{"name":"test1"}]}
hello
Customize the HttpMessageConverters :
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Set.class, new SharedUserDeserializer());
objectMapper.registerModule(module);
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
Reference here : https://dzone.com/articles/customizing
Try deserialize only "Set" -> extends JsonDeserializer< Set >

SPRING REST: Removing empty objects from response in JSON format

I don't have option of spring.xml so i went by annotated method.
I have below REST Interfaces in package : com.dpk.cm.impl.ecommerce.rest
and implementation in com.dpk.cm.impl.ecommerce.rest.services
I created one spring config class: but seems like i am still seeing in my JSON response empty objects.
Below is my code :
#Configuration
#ComponentScan(basePackages = "com.dpk.cm.impl.ecommerce.rest")
#EnableWebMvc
public class SpringConfig extends WebMvcConfigurerAdapter {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
final ObjectMapper objectMapper = new ObjectMapper();
// objectMapper.setSerializationInclusion(Inclusion.NON_EMPTY);
objectMapper.setSerializationInclusion(Include.NON_EMPTY);
converter.setObjectMapper(objectMapper);
converters.add(converter);
super.configureMessageConverters(converters);
}
}
How to remove the Empty Objects from the JSON Reponse Object.
I had similar requirement, but though I use CXF framework on spring boot, there spring boot was creating ObjectMapper which was overriding configuration. Hence I was manually create ObjectMapper as shown below.
#Bean(name = "objectMapper")
public ObjectMapper getObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(
SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, false);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY,
true);
mapper.setSerializationInclusion(Include.NON_NULL);
return mapper;
}
You can create your custom serializer where you can add a condition on serialization of the object.
Model
#JsonSerialize(using = IgnoreEmptyPersonSerializer.class)
public class Person {
private String name;
private String address;
public Person(String name, String address){
this.name = name;
this.address = address;
}
...
//setters and getters
...
}
Custom Serializer
public class IgnoreEmptyPersonSerializer extends JsonSerializer<Person> {
#Override
public void serialize(Person value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
String name = value.getName();
String address = value.getAddress();
//Dont serialize it if it is empty
if((name == null || name.trim().equals("")) &&
(address == null || address.trim().equals(""))){
return;
}
jgen.writeStartObject();
jgen.writeFieldName("name");
jgen.writeString(value.getName());
jgen.writeFieldName("address");
jgen.writeString(value.getAddress());
jgen.writeEndObject();
}
}

Categories

Resources