JsonDeserializer<Date> is not invoked - java

I am making a web application which makes a REST call to return me the list of order. The order has list of products and each product has expiry date. So, something like this
{
"order": 123,
"products" :[
{
...
"expiryDate": "2015 January 01",
...
}
]
}
I obviously needed to generate the POJO and because there are so many fields I choose this tool http://www.jsonschema2pojo.org/
I want to convert this String date to java.util.Date and to do that, I have created a custom date serializer and put this annotation on product expiry setter method
#JsonDeserialize(using = CustomJsonDateDeserializer.class)
public void setExpiryDate(Date date) {
...
}
// Different Class
public class CustomJsonDateDeserializer extends JsonDeserializer<Date>
{
#Override
public Date deserialize(JsonParser jsonparser,
DeserializationContext deserializationcontext) throws IOException, JsonProcessingException {
....
}
}
However, deserialize() method doesn't get invoked at all. I also put in the #JsonDeserialize to the field where it is declared but it is still not work.
Could anyone tell me where I am going wrong? Thanks for the help

Related

Jackson preprocess json before sending to deserialization

I have a JSON string which I would like to translate into POJO using ObjectMapper.readValue method.
The thing is that the input Json string contains keys which I would like to filter out before the deserialization.
I came across DelegatingDeserialization class which according to my understanding allows you to extend it and override one of the deserialize method to reconstruct the json input and then pass it on the chain.
The thing is that I try to enable this custom delegating deserializer by adding the
#JsonDeserialize(using = CustomDelegatingDeserialization.class) on top of my Pojo - is that the right way to instantiate it??
Here is a snippet of my custom delegator:
public static class CustomDeserializer extends DelegatingDeserializer {
public CustomDeserializer() {
super(null);
}
public CustomDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(defaultDeserializer);
}
#Override
protected JsonDeserializer<?> newDelegatingInstance(JsonDeserializer<?> newDelegatee) {
return new CustomDeserializer(newDelegatee);
}
#Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
return super.deserialize(restructure(p), ctxt);
}
private JsonParser restructure(JsonParser jp) throws IOException {
...
return newJsonParser;
}
}
Am I taking the right path or there is a more fitting solution??
THank you!
EDIT 1
Another approach is to have a CustomJsonDeserializer extends JsonDeserializer<T> and override its deserialize method then reconstruct the Node and propagate it by returning codec.treeToValue(jsonNode, Pojo.class); this makes sense BUT it gets me into infinite loop! any idea why?
Assuming your POJO doesn't have a property that you would like to ignore you can use annotation #JsonIgnoreProperties(ignoreUnknown = true)for your class. That tells Jeckson to ignore properties that are not present in your POJO. Read more on the issue how to ignore some properties here: Jackson Unmarshalling JSON with Unknown Properties

JsonSerialize / JsonDeserialize not working in Apache Tomcat (TomEE)

LATER EDIT 2019-05-31
If I write a sample main method which instantiates an Item and then call String s = new ObjectMapper().writeValueAsString(item);, then the custom serializer is called correctly and has effect.
The issue only appears when the whole app is deployed in an Apache TomEE server.
LATER EDIT: it's not an issue with placement of annotation (on field vs. on getter), I tried various combinations of this (annotation on getter, annotation on private field, annotation on public field, etc...)
The code:
import com.fasterxml.jackson....
// YES, all JSON-related stuff is from fasterxml
#JsonAutoDetect
public class Item {
private Date lastModified;
#JsonSerialize(using = CSer.class)
public Date getLastModified() {
return lastModified;
}
public class CSer extends JsonSerializer<Date> {
public SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
#Override
public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeString(dateFormat.format(value));
}
}
}
// some place else, in a REST service class
...
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getItems(... {
...
return Response.ok(result.getData()).build();
// result.getData() is an ArrayList of "Item" objects.
}
The ISSUES:
from what I know, the default JSON output format of the date should be the timestamp. In my case, it's not, instead it's yyyyMMddHHmmssZ
the custom serializer has no effect, I cannot change the output format of the date, and the serialize method never gets called.
The jackson files in my lib folder: jackson-annotations-2.8.0.jar, jackson-core-2.8.8.jar, jackson-databind-2.8.8.1.jar.
What am I doing wrong ?
Thank you.
It might have something to do with your annotation being placed on the getter - you might move it to reflect something similar to
public class Item {
#JsonSerialize(using = CSer.class)
private Date lastModified;
// ...
}
or you have to configure Jackson to only use getters for serialization.

Json array not serializing properly

I am trying to Json serialize and deserialize LocalDate array in my Java class but when i generate json schema for the web service, the parameter still shows up as LocalDate rather than String.
Following is the code :
#JsonSerialize(
contentUsing = ToStringSerializer.class
)
#JsonDeserialize(
contentUsing = LocalDateFromJSON.class
)
private LocalDate[] amortizationDates;
and in Json schema this appears as :
amortizationDates":{"type":"array","items":{"$ref":"#/definitions/LocalDate"}}
which is wrong because it should appear as String when serialized.
Any ideas on how to serialize it as String.
Edit:
I am suing Jackson for serialization and following are serializer details :
com.fasterxml.jackson.databind.ser.std.ToStringSerializer- Jackson inbuilt
LocalDateFromJSON ->
public static class LocalDateFromJSON extends JsonDeserializer<LocalDate> {
public LocalDateFromJSON() {
}
public LocalDate deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
return LocalDate.parse(((TextNode)jsonParser.readValueAsTree()).asText());
}
}

Jackson JSON Array Value Deserialization

I am trying to de-serialize this JSON object using Jackson 2.8 as part of Retrofit response. Here is the JSON response I get from the server.
{
"id":"8938209912"
"version":"1.1"
"cars":{
"mercedes":[
{
"property":"color"
},
{
"property":"price"
},
{
"property":"location"
}
],
"tesla":[
{
"property":"environment"
}
]
}
}
Based on the query, the cars above may have one or more models returned. I cannot create a class each for each model as these get created/removed arbitrarily. For each model of the car (say tesla), there may be one or more property key-value pairs.
I am new to Jackson. I have been looking at several examples and looks like a custom #JsonDeserialize is the best way to go. So, I created Root class and Cars class like this:
// In file Root.java
public class Root {
#JsonProperty("id")
private String id = null;
#JsonProperty("version")
private String version = null;
#JsonProperty("cars")
private Cars cars = null;
}
// In file Cars.java
public class Cars {
public Cars(){}
#JsonDeserialize(using = CarDeserializer.class)
private Map<String, List<Property>> properties;
public Map<String, List<Property>> getProperties() {
return properties;
}
public void setProperties(Map<String, List<Property>> properties) {
this.properties = properties;
}
}
// Property.java
public class Property {
#JsonProperty("property")
private String property;
}
My de-serializer is below. However, even though the empty constructor gets called, the parse method itself is not called at all!
// CarDeserializer.class
public class RelationshipDeserializer extends StdDeserializer<Map<String, List<Action>>>{
protected RelationshipDeserializer(){
super(Class.class);
}
#Override
public Map<String, List<Action>> deserialize(JsonParser parser, DeserializationContext ctx)
throws IOException, JsonProcessingException
{
// This method never gets invoked.
}
}
My questions:
Is this the right approach in the first place?
Why do you think the execution never gets to the deserialize()? (I checked, the cars object is present in JSON.
Are there better approaches to parse this JSON using Jackson?
The "properties" deserializer is never called because that does not match anything in that JSON. The field name in the JSON is "property" and it does not match Map<String, List<Property>>. It looks like it would be closer to List<Property>
Do you control the in coming JSON? It would be better for the car name/type to be in its own field rather than the name of the object. Then you can use a generic object. What you have now is going to break. Any time they add a new name/type and you do not have a matching object for it.

Jackson Custom Deserializer breaks default ones

I'm currently implementing parsing of JSON to POJO.
My Model class looks like this:
public class InvoiceModel {
#JsonDeserialize(using=MeteorDateDeserializer.class)
Date date;
String userId;
String customerName;
ArrayList<PaymentModel> payments;
[...getters, setters...]
}
a JSON string could look like this:
{
"date": {
"$date": 1453812396858
},
"userId": "igxL4tNwR58xuuJbE",
"customerName": "S04",
"payments": [
{
"value": 653.5,
"paymentMethod": "Cash",
"userId": "igxL4tNwR58xuuJbE",
"date": {
"$date": 1453812399033
}
}
]
}
though the payments field may be omitted. Anywho, doesn't really matter too much for the question. You see, the format for parsing the date is somewhat "odd" as in it is encapsulated in the "$date" property of the "date" object. This is however not in my control.
To get around this problem I wrote a custom JSON Deserializer to use for this date property. It looks like this:
public class MeteorDateDeserializer extends org.codehaus.jackson.map.JsonDeserializer<Date> {
#Override
public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
// parse the "$date" field found by traversing the given tokens of jsonParser
while(!jsonParser.isClosed()){
JsonToken jsonToken = jsonParser.nextToken();
if(JsonToken.FIELD_NAME.equals(jsonToken)){
String fieldName = jsonParser.getCurrentName();
jsonToken = jsonParser.nextToken();
if("$date".equals(fieldName)){
long timeStamp = jsonParser.getLongValue();
return new java.util.Date(timeStamp);
}
}
}
return null;
}
}
The exact problem is the following:
The returned InvoiceModel POJO has every attribute apart from "date" set to null, whereas the date is parsed fine. I have narrowed down the problem to the custom Date Deserializer by not deserializing the date at all (just deserializing the 2 string values and the payments array, which works fine).
My thesis is that the annotation conveys to Jackson that the custom deserializer is to be used for the whole class instead of being used just for the date field.
According to the doc this should not be the case:
Annotation use for configuring deserialization aspects, by attaching to "setter" methods or fields, or to
The call to the serialization is nothing special. It's just a standard ObjectMapper call.
InvoiceModel invoice = mapper.readValue(s2, InvoiceModel.class);
where s2 is the JSON string.
My version of Jackson is 1.9.7

Categories

Resources