Jackson parse json with unwraping root, but without ability to set #JsonRootName - java

The rest service responds with
<transaction><trxNumber>1243654</trxNumber><type>INVOICE</type></transaction>
or in JSON:
{"transaction":{"trxNumber":1243654,"type":"INVOICE"}}
There is no problems when I use:
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true)
And as resulting class
#JsonRootName("transaction")
public class Transaction {
private String trxNumber;
private String type;
//getters and setters
}
But actually I should use the Transaction class from 3rd party jar, which is exact like above, but has no #JsonRootName("transaction") annotation.
So I end up with
Could not read JSON: Root name 'transaction' does not match expected ('Transaction') for type...
Is there any ways to force Jackson parse to Transaction class without adding any stuff to the Transaction class itself (as I get this file as part of a binary jar)?
I've tried custom PropertyNamingStrategy, but it seems has to do only with field and getter/setter names, but not class names.
Java7, Jackson 2.0.5.
Any suggestions? thanks.

You can do it with mixin feature. You can create simple interface/abstract class like this:
#JsonRootName("transaction")
interface TransactionMixIn {
}
Now, you have to configure ObjectMapper object:
ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
mapper.addMixInAnnotations(Transaction.class, TransactionMixIn.class);
And finally you can use it to deserialize JSON:
mapper.readValue(json, Transaction.class);
Second option - you can write custom deserializer for Transaction class.

Related

Java Polymorphic Json Deserialization

I am using jackson as part of serializing and deserializing in my project (Spring Java).
In normal scenarios where I have interface(contract) acting as field in POJO,
then I use #JsonTypeInfo and #JsonSubTypes to achieve deserialization in polymorphic cases.
But, right now, I have scenariio something like this:
public class classA {
private contractA fieldA;
//constructor and getter-setters.
}
then,
public interface contractA {
}
and finally,
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(/* concrete-class1 as name-value */),
#JsonSubTypes.Type(/* concrete-class2 as name-value */),
})
public interface contractB extends contractA {
//contract methods.
}
Now, when classA is passed as controller request body and I pass fieldA as concrete-class1 or concrete-class2,
JsonSubTypes are not being used by jackson to deserialize into one of them.
The reason why I did this and had two contracts is due to package dependencies. contractB
is in different package as of contractA's.
How can I configure on contractA using jackson that this class has its JsonSubTypeInfo specified in its subclasses.
Or, any other libraries or approaches are also welcomed.
Thank you !
This problem is later on solved by introducing our own custon JsonTypeInfo.
When the application is under deployment, we fetch all subclasses which is present in the JsonTypeInfo annotation (jackson like custom annotaion) and maintain a data-structure, that will be used while serializing and deserializing. This process is somewhat similar to the Jackson one (in addition to lookup for nested hierarches as well).

Deserialize JSON for a class I dont own with custom getters

I am trying to deserialize an object of a class that I do not own. The class has attribute names such as id_, address_, name_, but its getters are getId() getAddress() getName() etc.
When I try to deserialize the JSON using Jackson, I get
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "id_", not marked as ignorable
It looks like this happens because Jackson's looking for getId_() instead of getId(). Since I do not own the underlying class, I cannot use Jackson's annotations to map attributes to custom json fields.
How can I deserialize with a custom mapping of object attributes to its getter methods?
You can try a custom deserializer.
check out: https://www.baeldung.com/jackson-deserialization
This way you can register a deserializer for the class.
However, you still have to edit it when the class changes.
One other thing you can try:
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
This will give the mapper full access to private members.
You can apply a MixIn for Jackson - that's how I solved my issue trying to serialize and deserialize JSON for an auto-generated AVRO class (Avro generated class issue with json conversion [kotlin])
Here is an example:
https://medium.com/#shankar.ganesh.1234/jackson-mixin-a-simple-guide-to-a-powerful-feature-d984341dc9e2

Jackson is ignoring XmlAccessorType.NONE

My pojo class is annotated with XmlAccessorType.NONE.
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
public class Human {
#XmlElement(name="name")
private String name;
private int age
}
JSON which im trying to read contains both properties name and age. If i annotate the class with JsonIgnoreProperties(ignoreUnknown = true) everything works However if i try to use annotation XmlAccessorType(XmlAccessType.NONE) intead, jackson throws unknown property exception.
I tried to add JaxbAnnotationIntrospector into objectmapper but it did not help mapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector());
I don't see why XmlAccessorType(XmlAccessType.NONE) would be relevant here,
It would affect discovery of properties available (no auto-discovery), but NOT what to do with JSON/XML properties for which there is no Bean property.
The difference here is probably more due to difference between defaults for JAXB and Jackson: by default, JAXB silently ignores anything it does not recognize. By default Jackson throws an exception when it does not recognize something.
If you want, you can configure ObjectMapper to ignore these problems by default:
napper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
so that behavior is similar to that of JAXB.

Serialization and Deserialization with Jackson: how to programmatically ignore fields?

I'm using Jackson to serialize and deserialize objects. The problem is that sometimes I want to show a field and sometimes not.
Actually I'm using the #JsonIgnore to avoid the printing of the property when I don't need it. When I need it I'm disabling the Property through
mapper.getSerializationConfig().disable(SerializationConfig.Feature.USE_ANNOTATIONS);
but this will disable also other annotations that I need.
How can I get the result that I need? Using Views? Any example?
A little pojo to understand what I want:
class User {
private String username;
#JsonIgnore
private String password;
// getter setter
}
writeToDB() {
mapper.getSerializationConfig().disable(SerializationConfig.Feature.USE_ANNOTATIONS);
mapper.writeValueAsString(user);
}
and through the REST API you can get the username without the password (thanks to the JsonIgnore)
In the end I've handled this in a different way. I was using Jersey and Guice so was a little hard to find out how, but I did it.
Basically I used the MixIn annotations of Jackson but using Jersey I had to create the ObjectMapper into a Provider and then bind it with Guice.
In this way when I'm using the REST service Jersey will use the ObjectMapper defined in the Provider; when storing the stuff Jackson will use the standard ObjectMapper.
Now some code.
create the PrivateUser class:
public abstract class PrivateUser {
#JsonIgnore abstract String getPassword();
}
create the provider:
#Provider
public class JacksonMixInProvider implements ContextResolver<ObjectMapper> {
#Override
public ObjectMapper getContext(Class<?> aClass) {
final ObjectMapper mapper = new ObjectMapper();
mapper.getSerializationConfig().addMixInAnnotations(User.class, PrivateUser.class);
return mapper;
}
}
and bind it:
bind(JacksonMixInProvider.class).asEagerSingleton();
That's it! :D
Hope this will help someone else to waste less time!
I think you should handle this a different way, by creating a custom Jackson serializer that can selectively serialize/ignore the password.
Annotations like this should be considered immutable at runtime. There may be some reflection trick to extract the JsonIgnore and set the value, but, if so, this would be really heavy-handed.

JsonTypeInfo does not serialize when using Jackson with Jersey

I annotated a JAXB class with JsonTypeInfo so that I could serialize polymorphic classes easily. However, the annotation does not show up when serialized by Jersey. To be more specific, it shows up when using ObjectMapper but not as a return type from a resource. I am very confused right now as this seems to be a problem with Jersey => Jackson interaction.
To debug things, I used the jsonfromjaxb example from the jersey-samples to localize my problem. I added the following to the Flights class to have it serialize out to #class.
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
I have the following methods available in the resource, one which just returns the JAXB object and one which manually uses ObjectMapper
#GET
#Produces({"application/json"})
public synchronized Flights getFlightList() {
return myFlights;
}
#GET
#Path("/object_mapper")
#Produces({"application/json"})
public synchronized String getFlights() throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsString(myFlights);
}
The result of querying /jsonfromjaxb/flights
{"flight":[{"flightId":"OK123","company":"Czech Airlines","number":123,"aircraft":"B737"},{"flightId":"OK124","company":"Czech Airlines","number":124,"aircraft":"AB115"}]}
The result of querying /jsonfromjaxb/flights/object_mapper
{"#class":"com.sun.jersey.samples.jsonfromjaxb.jaxb.Flights","flight":[{"number":123,"company":"Czech Airlines","aircraft":"B737","flightId":"OK123"},{"number":124,"company":"Czech Airlines","aircraft":"AB115","flightId":"OK124"}]}
Thanks,
Ransom
I think it looks like you aren't using Jackson-based serialization (that is, one that uses ObjectMapper; low-level jackson generator is used for most JSON output, including ones where binding is done differently). If you were, it definitely should look like what you see from explicit use. So it seems to be matter of changing Jersey JSON configuration.

Categories

Resources