Allow NULL map values in a custom JsonSerializer - spring

I have a global object mapper in spring whose property is set like this:
getObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
This is working correctly and excluding all the null values while serializing.
But I have a custom serializer for a class which has private Map<String, Object> data = new LinkedHashMap<>() as a member variable. This map has keys which have null values which I would like to include in my output. Class level or member level #JsonInclude is not working. Tried overriding isEmpty and returning false always, but it didn't work.
NULL map values were automatically included until Jackson 2.5 but this started happening after upgrade to 2.9+. Any help would be appreciated.

Basically what you are looking for is a custom Serializer only for one class right?
you can find how it is achieved here
And then you can register the serializer to your class
#JsonSerialize(using = CustomSerializer.class)
class YourClass{
This will register the custom serializer to your interested class and this way you can add null values as well.

Related

#Value injection of field not working in case of an empty Map

I am trying to inject a map property inside my spring-component class using #Value annotation.
My class is something like this
#Service
class SomeService {
#Value("#{\${some.map.property}}")
lateinit var map: Map<String, Boolean>
}
If my application.properties is as -
some.map.property={a:true}
The injection works fine. But if the value is empty i.e. something like this
some.map.property={}
The application throws an error lateinit property map has not been initialised. Is there a way in spring to initialise the map to an empty map if the value of the property is {}.I have a condition that this property will always be there and only the value of the property can change. I am using spring boot version -> 2.7.1 and the app is built using Kotlin.
If the property is set to {}, then I am getting property uninitialised error. If the value is present it works fine.
Given I always have to keep the property and can only change the value. Is there a way to initialise the property with an empty map if the value is {}.
I can always read the property as string and do a conversion to Map. But I want to avoid that.
Thanks!
So the problem with your code is that whenever you pass:
some.map.property={}
You will receive:
kotlin.UninitializedPropertyAccessException: lateinit property map has not been initialized
Because {} is mapped to null, but you are expecting to have Map<String, Boolean> that's why you have a problem.
The solution is simple, you can use the default value if null occurs:
#Value("#{\${some.map.property}}")
val map: Map<String, Boolean> = emptyMap()
In that case for {} value in your property it will be mapped to empty map.

Remove null attributes from request body Spring Boot

I'm new to spring boot and was referring to this article. It asks to add #JsonInclude(Include.NON_NULL) annotation to remove null attributes from response body, however I'm interested in removing null attributes from request body.
Please suggest how can I achieve that.
The request body is:
{
"userUuid": "2u9k2ld8f-ghj47dhj",
"suggestion": null
}
and the request DTO class is:
#Data
#NoArgsConstructor
public class UserRequestDTO implements Serializable {
private String userUuid;
#JsonInclude(JsonInclude.Include.NON_NULL)
private String suggestion;
}
Clearly it is not working for me. When I stringify and print the request body, it includes suggestion attr which is null.
Thank you for any help.
Well... Do not use toString() use Jackson ObjectMapper. So like:
var objectMapper = new ObjectMapper();
var dto = objectMapper.readValue(JSON, UserRequestDTO.class);
var strNoNullFields = objectMapper.writeValueAsString(dto);
That way the annotation is working.
Anyway this is not something very optimal. You might want to re-think your design how to calculate checksum (your question smells a bit like XY-problem).
I need to generate the checksum of the payload excluding the null attrs. I do not want to replace null attr rather remove it. To generate the signature I will to doing .toString() on the request body
I think you are looking for a request has dynamic attributes.
Try use a HashMap<String,Object> on parameters.
Other simple way is overriding toString() from DTO and ignore null attrs.
Suggestions: Besides using this only for logging I think both is bad practice could be better create a method generateSignature() handles all rules of this.

Jackson deserializer priority?

I have a Spring Boot app that is modeling ActityStreams objects and for the most part Jackson's Polymorphic Deserialization works well.
There are 'objects' in the JSON which are references (links) and not JSON objects with type information. For instance
"actor":"https://some.actors.href/ rather than
"actor":{
"type":"Actor",
"name":"SomeActor"
}
I've written custom deserializers and and placed them on the fields to deal with this
#JsonDeserialize (using = ActorOrLinkDeserializer.class)
private Actor actor;
However my ActorOrLinkDeserializer is instantiated but never called and Jackson complains with Missing type id when trying to resolve subtype of [simple type, class org.w3.activity.streams.Actor]: missing type id property 'type' (for POJO property 'actor') which is from the polymorphic deserializer.
It appears that the polymorphic deserialization code takes precedence over my local #JsonDeserialize annotation and I need a way to force my code to run first.
I've tried using my own ObjectMapper rather than Boot's and there's no difference.
I'd appreciate pointers and suggestions.
It turns-out there's a fairly simple solution to this problem using a DeserializationProblemHandler.
What I've implemented that works for all test cases so far is
1.
objectMapper.addHandler(new DeserProblemHandler());
or register with Spring Boot.
2.
public class DeserProblemHandler extends DeserializationProblemHandler {
public JavaType handleMissingTypeId(DeserializationContext ctxt, JavaType baseType, TypeIdResolver idResolver, String failureMsg) {
return TypeFactory.defaultInstance().constructType(baseType.getRawClass());
}
}
Add a constructor to each of the polymorphic classes that takes a string argument which is the href.

Resttemplate unable to parse array of type T

I'm facing a problem with Spring and restTemplate. I want to send an object (ListResponse) that contains a generic array. The defenition is as follow:
public class ListResponse<T> implements Serializable {
private long total;
private int page;
private int pageSize;
private T[] objects;
I send a request whith restTemplate.getForObject(). As a result I get an object of type ListResponse but the objects array contains an array of LinkedHashMaps instead of an array with objects of type T.
It seems like restTemplate can not convert the elements in the array to their correct type.
How can I make sure that I get an array of objects of type T back ?
I had this problem today and here is the solution that I came up with (actually, that one of my co-workers suggested). We use it with an interface that returns List<MyDto>.
When you call the RestTemplate, don't pass in the generic type.
Define: public class MyDtoListTemplate extends ListTemplate<MyDto>
Then, call
MyDtoListTemplate template = restTemplate.getForObject("url", MyDtoListTemplate .class, mapOfPathVariables);
It's a bummer that you have to define a concrete class that extends/implements the generic type, but then the generic information is available to the jackson deserializer.
I remember I was able to deserialize generic classes with Jackson 2. I had to add MappingJackson2HttpMessageConverter converter to RestTemplate before making any Http calls with it.
RestTemplate template = new RestTemplate();
template.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
Unfortunately there's no easy way of doing it that I know of. The problem is that the RestTemplate is told which object type to expect. As long as all the fields in this object has a corresponding element in the json/xml, everything works fine. In the case of generics, the serializer doesn't know which class to expect so it just turns the map it gets to a java Map.
You will have the same problem if you tried to getForObject for a generic return type.

Spring JDO - makePersistent not returning created object

I'm using Spring and JDO connecting to a MySQL database.
When I persist an object, I am expecting to see the created object returned by the makePersistent() method. It does return an object, but this object only has the ID of the newly created object. All the other fields that were persisted now have a value of null.
In the code example below, I insert a value of 12 with the carouselNumber. The returned object has that value set to NULL and the id has the newly created ID value from the database.
I've used JDOHelper.getObjectState() and found that my object is in a Transient state.
I'm wondering if there is some annotation that I am missing to tell JDO to return all the values on the object, rather than just the newly generated ID.
EDIT:
I've done some further exploring and found that when I use the raw Datanucleus JDP API that thsi works fine. The problem only seems to be when I use Spring's JDO template. I'd really like to get an understanding of why this differs. Thanks
Thanks in Advance,
Brian.
#PersistenceCapable(table = "CAROUSEL", identityType = IdentityType.APPLICATION)
public class Carousel {
#PrimaryKey(column = "ID")
#Persistent(valueStrategy = IdGeneratorStrategy.INCREMENT)
private Long id;
#Column(name = "CAROUSEL_NUM")
private int carourselNumber;
......
public class CarouselDAOImpl extends JdoDaoSupport implements ICarouselDAO {
public Carousel insert(Carousel carousel) {
return getJdoTemplate().makePersistent(carousel);
}
.....
The makePersistent method alters the carousel object you've passed in to generate an ID, so it doesn't need to return anything. Just make your method void and use the carousel you've passed in.

Resources