Jackson - Use custom deserializer only for specific JSON - java

We have a class containing multiple Sets of Longs. We want them serialized as arrays, and most clients do so.
However, we have a PHP client that creates sets such that they serialize in an odd way. A set with the number 4 comes in like this:
"setOfNumbers": {
"4": 0
},
Naturally, Jackson complains about this being an object and not an array. What I would like is to have a custom deserializer that is only invoked if Jackson detects an object where a Set<Long> should be (and ideally only if they are contained in specific classes.)
I've tried this:
this.addDeserializer(Set.class, new StdDelegatingDeserializer<>(new StdConverter<Map<String, Long>, Set<Long>>() {
#Override
public Set<Long> convert(Map<String, Long> set) {
return parseLongs(set);
}
}));
The problem with this is that now it expects an object instead of an array for all Set fields. The class being deserialized is generated, so I can't add any annotations or make other changes.

If the generated class has always the same name you can try with Json Jackson Mix-in annotations as shown in this example

Related

How to Parse untyped, nested JSON with Polymorphism?

I am using Feign to hit external APIs, and then to process the externally generated JSON (aka, the response data cannot be modified in any way), and I am trying to bundle these together into an extensible super type. At this point, I am not even sure if what I am trying to do is possible with Jackson / Feign. If it would be much easier to abandon (or heavily restructure) the polymorphism, I think I am also ready to give up on it and just create a bunch of sub classes.
Here are my two main questions, with more context below.
Should I just separate the easily deduced types from the complex types, and have a little more duplicated boiler plate?
How can I create a custom deserializer for the list object I linked? Ideally I would like to have some way to populate the more boiler plate fields less manually -- as an example, it would be great if I could call default deserializers inside it, which would rely more on the standard annotations in other objects.
Ideally, I would like one class, like this:
public final class BillApiResponse {
#Valid
#JsonProperty("response_status")
private boolean responseStatus;
#Valid
#JsonProperty("response_message")
private String responseMessage;
#JsonProperty("response_data")
private BillApiResponseData responseData;
//getters and setters, etc.
}
and then I would to have Jackson automatically map the simpler objects in whatever way is easiest (LoginResponse, LoginError), while I would try to implement a custom handler for the more complex objects (UpdateObject, ListOfObjects).
So, something like this:
#JsonTypeInfo(use = Id.DEDUCTION)
#JsonSubTypes({
#Type(value = BillLoginSuccess.class),
#Type(value = BillErrorResponse.class),
//#Type(value = BillResponseObject[].class) <--- This breaks things when added
})
// #JsonTypeResolver(value = BillResponseTypeResolver.class) <--- Open to using one of
// these if I can figure out how
// #JsonDeserialize(using = BillResponseDeserializer.class) <--- Also open to using a
// custom deserializer, but I would like to keep it only for certain parts
public interface BillApiResponseData {}
Here is a link to the API specification I am trying to hit:
Get a List of Objects
This returns an untyped array of untyped objects. Jackson does not seem to like that the array is untyped, and stops parsing everything there. Once inside, we would have to grab the type from a property.
{
"response_status" : 0,
"response_message" : "Success",
"response_data" : [{
"entity" : "SentPay",
"id" : "stp01AUXGYKCBGFMaqlc"
// More fields
} // More values]
}
Login
This returns a totally new object. Generally not having issues handling this one (until I add support for the above list, and then all of the parsing breaks down as Jackson throws errors).
Update Object
This returns an untyped object. Once again, we would have to go inside and look at the property.
I have tried a number of things, but generally I was not successful (hence I am here!).
These include:
Trying to hook into the lifecycle and take over if I detect an array object. I believe this fails because Jackson throws an error when it sees the array does not have a type associated with it.
SimpleModule customDeserializerModule = new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(
DeserializationConfig config,
BeanDescription beanDesc,
JsonDeserializer<?> defaultDeserializer) {
if (beanDesc.getBeanClass().isArray()) {
return new BillResponseDeserializer(defaultDeserializer);
} else {
return defaultDeserializer;
}
}
});
Custom Deserializers. The issue I have is that it seems to want to route ALL of my deserialization calls into the custom one, and I don't want to have to handle the simpler items, which can be deduced.
TypeIdResolvers / TypeResolvers. Frankly these are confusing me a little bit, and I cannot find a good example online to try out.

Is there a custom Json Serializer pattern to serialize a property differently including the property's key name?

I have a class that needs to be serialized
public class Abc
{
private long age;
private JaxBElement<Foo> fooWrapper;
// other properties
}
The expected output JSON is
{
"age": 24,
"my_own_key": "my_own_value" // the key should not be "fooWrapper"
A constraint is that the original class Abc cannot be modified since it is generated out of xjc and I don't want to explore custom class using bindings yet.
I have tried custom serializers, bean modifiers etc. for the JaxBElement and all of them allow me to control the serialization. But they work at the VALUE of the property only. They don't allow me to change stuff at the "KEY-VALUE" level. This is the crux of the question. The key is already written out for the property before the custom serializer is invoked to control the value.
E.g. My custom serializer is invoked only after the Jackson system has emitted out the key
"fooWrapper": // now for the value part, let me invoke the custom serializer
So the output JSON always contains the "fooWrapper" key.
{ "fooWrapper": { "any-key": "any-value" } }
// the fooWrapper is already emitted out. That is what needs to be controlled.
My ask is to control the serialization at a higher level, such that both the key and value can be controlled. So when class Abc is being serialized, the fooWrapper property should not be written as a key at all and some custom serializer should be invoked.
Another constraint is that there are several classes like Abc which may have such JaxBElement. It is not known ahead of time. So there needs to be a generic way to attach the custom serializer.
The pseudo ask is really that we be able to attach a custom serializer to any class which has a property that matches a pattern such that the serializer can control the name of the property (or the whole key-value blob) written out.
Also, the problem is not specific to JaxBElement per se. It could be any property. The problem is more about controlled serialization INCLUDING the key being written out.
Maybe you just use the incorrect kind of Serializer. This post, although a bit old should show you how to do what you want with StdSerializer.
This kind of serializer allows you to control both the key and the value.
If you want to control serialisation of key-value pair you need to register custom serialiser not only for JaxBElement<Foo> fooWrapper but also for Abc class to change a key value.
Since it is not a generic solution you can also try to create MixIn class or interface and provide extra configuration:
interface MixInA {
#JsonSerialize(using = JAXBElementJsonSerializer.class)
#JsonProperty("newProperty")
JAXBElement<Foo> getFooWrapper();
}
See also:
What is equivalent code settings for #JSonIgnore annotation?
Make Jackson serializer override specific ignored fields
Downside of this solution is you have to find all types for which you have to register MixIn class or interface. In case fields are different you need to create many different getters or many different MixIn interfaces to cover them all.
So, probably them most flexible solution would be to implement custom com.fasterxml.jackson.databind.AnnotationIntrospector and for given type you can return custom serialiser and custom name. Simple example:
class DynamicJaxbAnnotationIntrospector extends AnnotationIntrospector {
#Override
public Version version() {
return new Version(1, 0, 0, "Dynamic JaxbElement", "your.package", "jackson.dynamic.jaxb");
}
#Override
public Object findSerializer(Annotated am) {
if (am.getRawType() == JAXBElement.class) {
return new JAXBElementJsonSerializer();
}
return super.findSerializer(am);
}
#Override
public PropertyName findNameForSerialization(Annotated a) {
if (a.getRawType() == JAXBElement.class) {
return new PropertyName("newProperty");
}
return super.findNameForSerialization(a);
}
}
See also below article how to use it:
How to serialise Enums as both Object Shape and default string?

Using different classes to map JSON data with GSON

My application is receiving JSON messages from a WebSocket connection.
There are different types of answers, which are formatted like that:
{
"type": "snapshot",
"product_id": "BTC-EUR",
"bids": [["1", "2"]],
"asks": [["2", "3"]]
}
or
{
"type": "l2update",
"product_id": "BTC-EUR",
"changes": [
["buy", "1", "3"],
["sell", "3", "1"],
["sell", "2", "2"],
["sell", "4", "0"]
]
}
... for example (see full API here).
Depending on the "type", I would like GSON to map a different class (e.g. Snapshot.class and l2update.class).
I have message handlers that subscribe to the WebSocket connection and I want the message to be processed by the relevant handler. For instance:
ErrorMessageHandler would manage the errors
SnapshotMessageHandler would create the initial order book
L2UpdateMessageHandler would update the order book
and so on
My problem is to dispatch the messages depending on their type.
I was thinking to convert them to the appropriate class and then call the relevant handler using a factory. I'm currently stuck at the first step, converting the JSON in Error.class or Snapshot.class depending on the "type".
How can I do that?
For Gson you could use com.google.gson.typeadapters.RuntimeTypeAdapterFactory.
Assuming you have - for example - following classes:
public class BaseResponse {
private String type, product_id;
// rest of the common fields
}
public class Snapshot extends BaseResponse {
// rest of the fields
}
public class L2Update extends BaseResponse {
// rest of the fields
}
then you would build following RuntimeTypeAdapterFactory:
RuntimeTypeAdapterFactory<BaseResponse> runtimeTypeAdapterFactory =
RuntimeTypeAdapterFactory
.of(BaseResponse.class, "type") // set the field where to look for value
.registerSubtype(L2Update.class, "l2update") // values map to 'type'
.registerSubtype(Snapshot.class, "snapshot");// value in json
Registering this with Gson will then enable automativcal instantiation of each type of responses:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(runtimeTypeAdapterFactory).create();
and provide BaseResponse for fromJson(..) if using it , like:
gson.fromJson( json , BaseResponse.class);
NOTE: that Gson omits de- & serializing the type field. However it needs to be set in Json. Just as it is now in responses you get.
You may want to consider using a library that requires a bit less of a solid object model, at least at first. I use JsonPath for this type of thing. You could use it to at least find out the type you're dealing with:
String type = JsonPath.read(yourIncomingJson, "$.type");
and then, based on the string, do a switch statement as #ShafinMahmud suggests.
However, you could use JsonPath for the whole thing too. You could read all of the values using the path notation and know how to parse based on the type.
Adding another library to read a single value may or may not work for you but if you use it to read other values it might end up being worthwhile.

Json Jersey Deserialize : Abstract Class

I'm trying to deserialize some JSON with Jersey/Jackson in Java.
Here is an example of my JSON
{
"text":"toto",
"link":"titi",
"items":[{
"text":"toutou",
"link":"tata",
"items":[{
"text":"toto2",
"link":"toutou2",
"data":"tonti",
]}
]}
}
So what my Java model parts looks like this
public IItem {
...
}
public Item implements IItem {
List<IItem> items;
String text;
String link;
...
}
public ItemData extends Item {
String data;
...
}
Now, when i try to deserialize my JSON, object mapper doesnt know what concrete class to Use.
How do I tell him this ? The thing is that I want an Item (with a list of Item (with a list of ItemData)).
I've though of only using one object containing all fields (text, link, data), but i'd prefer this type of design which appears better me. Do you think it's worth it ?
In reality I have more than one field that would replicate because JSON structure is a bit more complex, I've simplified it for sake of clarity.
Question2 : After that i need to serialise my objects again in JSON (first part is only for temporary development, I'll be filling objects from a JDBC driver later on), how can I tell jersey to only display one level at the time ?
i.e i request / I want the first level only, answer should be :
{
"text":"toto",
"link":"titi",
"items":[{
"text":"toutou",
"link":"tata",
]}
}
and if i request /tata answer should be :
{
"text":"toutou",
"link":"tata",
"items":[{
"text":"toto2",
"link":"toutou2",
"data":"tonti"
]}
}
(Question is more about how hiding the second level in my first request, I do understand how to handle the second request).
Thanks,
If your using Jackson, it has a feature that allows for proper deserialization in these kind of cases (polymorphic list of items). You can use the #JsonTypeInfo annotation to indicate you want the object type to be included in the JSON, which will then be used to deserialize the correct instances. Here's an example:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
public IItem {
// ...
}
This will add an attribute to each serialized representation of IItem, called #class, which Jackson will detect and use later on to deserialize the correct object instance.

Deserialize self referencing objects with Jackson

I have a JSON string looking like that (simplified):
[
{ "id":1, "friends":[2] },
{ "id":2, "friends":[1,3] },
{ "id":3, "friends":[] }
]
The content of friends are ids of other users in the list.
Is it possible somehow to create a Java class like the one below from the JSON just with Data Binding using Jackson or do I need an intermediate step for that?
public class User {
private long userid;
private List<User> friends;
// ... getters/setters
Thanks for your help.
There is no fully annotative way to do this, so you would need custom JsonSerializer / JsonDeserializer. Jackson 1.9 adds two new features that might help:
ValueInstantiators, so you can add constructors for deserializer to convert from basic integer into POJO
Value injection so you could pass additional context object (which you would need to find ids of already deserializer objects, to map then from integer to instance)
However I am not 100% sure how to combine these two features for specific use case...

Categories