Why is the Jackson Object Mapper unable to deserialize this nested JSON? - java

I am in the process of updating some code to hit a new API which returns the same type of data but in a different JSON format. This is a sample of the return from a request:
{
"code": 200,
"message": "OK",
"data": [
{
"start_time": "2017-09-20T00:00:00.000-04:00",
"end_time": "2017-09-21T00:00:00.000-04:00",
"value": 8612.637512577203
},
{
"start_time": "2017-09-21T00:00:00.000-04:00",
"end_time": "2017-09-22T00:00:00.000-04:00",
"value": 8597.89155775999
},
{
"start_time": "2017-09-22T00:00:00.000-04:00",
"end_time": "2017-09-23T00:00:00.000-04:00",
"value": 24584.603303989123
}
],
"meta": {
"space_id": "e1c38410-f912-4ae3-9db9-10a1ad1e3bf5",
"channel_id": 1,
"aggregation_type": "period_beginning",
"pids_count": 1,
"timezone": "America/New_York"
}
}
I want to ignore the code and message properties, and put the array of data into a list within a map, with the key being the "space_id" property (Map<String, List<Reading>>) for compatibility with the old implementation. Here is the POJO that I have created to contain the deserialized object:
#JsonIgnoreProperties({"code", "message", "meta"})
public class GetReadingsResult {
#JsonIgnore
private Map<String, List<Reading>> readings;
#JsonIgnore
public GetReadingsResult(Map<String, List<Reading>> readings) {
this.readings = readings;
}
#JsonCreator
public GetReadingsResult(#JsonProperty("data")Reading[] data, #JsonProperty("space_id")String spaceId) {
this.readings.put(spaceId, Arrays.asList(data));
}
//...other getters and setters...
}
In my test I am calling readValue on a test JSON file and getting the following error:
com.fasterxml.jackson.databind.JsonMappingException: Instantiation of [simple type, class model.GetReadingsResult] value failed: null
What is the proper way to set up/annotate my POJO to deal with this nested file?

This is the correct way to implement.
Please pay attention to object point of view of all thing:
These are the pojos:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"start_time",
"end_time",
"value"
})
public class Datum {
#JsonProperty("start_time")
public String startTime;
#JsonProperty("end_time")
public String endTime;
#JsonProperty("value")
public Double value;
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"space_id",
"channel_id",
"aggregation_type",
"pids_count",
"timezone"
})
public class Meta {
#JsonProperty("space_id")
public String spaceId;
#JsonProperty("channel_id")
public Integer channelId;
#JsonProperty("aggregation_type")
public String aggregationType;
#JsonProperty("pids_count")
public Integer pidsCount;
#JsonProperty("timezone")
public String timezone;
}
This is the wrapper root Object:
import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"code",
"message",
"data",
"meta"
})
public class ExampleStack {
#JsonProperty("code")
public Integer code;
#JsonProperty("message")
public String message;
#JsonProperty("data")
public List<Datum> data = null;
#JsonProperty("meta")
public Meta meta;
}
And this is the working example:
import com.fasterxml.jackson.databind.ObjectMapper;//<--IMPORTANT!
public class TestJacksonObject {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
ExampleStack stack = null;
try {
stack = mapper .readValue( new FileInputStream(new File("C://test.json")) , ExampleStack.class);
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(stack.message);//<--Do whatever you want...
.....
If it's too hard to produce all these classes, which is actually tedious I suggest you to autoproduce them online through this useful site:
Json2Pojo
Hope it helps you out!

Related

Generate json request body using Lombok annotation

I tried multiple pattern , but still no success how can I create JSON Array object with nested JSON object similar like below
{
"deduction": [
{
"id": "50258779",
"amount": {
"value": 13.24,
"currency": "INR"
},
"transfer": "DEPOSIT",
"fund": "RL",
"description": "TD description",
"code": "codeNumber"
},
{
"id": "50258779",
"amount": {
"value": 13.24,
"currency": "INR"
},
"transfer": "DEPOSIT",
"fund": "RL",
"description": "TD description",
"code": "codeNumber"
}
]
}
I had generated Class to build this request schema :
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
#Builder
#Getter
#Setter
#JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Transf{
private List<Deduction> deduction;
#Builder
#Getter
#Setter
public class Deduction {
private Amount amount;
private String transfer;
private String code;
private String fund;
private String description;
private Integer id;
}
#Builder
#Getter
#Setter
public class Amount {
private String currency;
private Double value;
}
}
Trying to create json request body to be send using rest assured
public Transf trans()
{
return Transf.builder()
.deduction(Transf.Deduction.builder().transfer("")).build();
}
But getting syntax error on this , need to know how can I make this work
Instead of
Transf.Deduction.builder().transfer("")
you need to have
Transf.Deduction.builder().transfer("").build()
First, you define private List<Deduction> deduction; --> you will supply List.
Second, to make builder work, you have to call .build()
public Transf trans() {
return Transf.builder()
.deduction(Arrays.asList(Transf.Deduction.builder().transfer("").build()))
.build();
}

How to deserialize JSON via JsonTypeInfo with unknown property

I need to deserialize JSON looks like the following:
{
"data": [{
"id": "id1",
"type": "type1"
"name": "John",
...
},
{
"id": "id2",
"type": "type2",
"name": "Rebecca",
...
},
{
"id": "id3",
"type": "unknown",
"name": "Peter",
...
}]
}
For deserializing JSON which I have written above I have created a couple of classes:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type",
defaultImpl = DefaultData.class
)
#JsonSubTypes({
#JsonSubTypes.Type(value = Type1Data.class, name = "type1"),
#JsonSubTypes.Type(value = Type2Data.class, name = "type2")
})
public class AbstractData {
public final String id;
public final String type;
public final String name;
public AbstractData(String id, String type, String name) {
this.id = id;
this.type = type;
this.name = name;
}
}
public class Type1Data extends AbstractData {
#JsonCreator
public Type1Data(#JsonProperty("id") String id,
#JsonProperty("name") String name
) {
super(id, "type1", name);
}
}
public class DefaultData extends AbstractData {
#JsonCreator
public DefaultData(#JsonProperty("id") String id,
#JsonProperty("type") String type,
#JsonProperty("name") String name
) {
super(id, type, name);
}
}
public class Main {
public static void main(String... args) {
ObjectMapper mapper = new ObjectMapper();
AbstractData data = mapper.readValue(json, AbstractData.class);
}
}
I get an exception if I use default implementation:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve type id 'unknown' as a type
The class DefaultData I need to avoid a deserialization exception if I will get the unknown type.
How can I fix this issue?
Summary
Right now it is not clear what is the exact root cause of the problem, because your example works for me with several corrections.
Still, please, consider the corrections as a draft.
Corrections
Data class for root object: Introduced
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
import java.util.StringJoiner;
public class RootData {
public final AbstractData[] data;
#JsonCreator
public RootData(#JsonProperty("data") final AbstractData[] data) {
this.data = data;
}
#Override
public String toString() {
return new StringJoiner(", ", RootData.class.getSimpleName() + "[", "]")
.add("data=" + Arrays.toString(data))
.toString();
}
}
AbstractData data class: Updated to deserialize type property
Please, see the Javadoc:
Note on visibility of type identifier: by default, deserialization (use during reading of JSON) of type identifier is completely handled by Jackson, and is not passed to deserializers. However, if so desired, it is possible to define property visible = true in which case property will be passed as-is to deserializers (and set via setter or field) on deserialization.
Updated annotation by adding visible = true:
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type",
visible = true,
defaultImpl = DefaultData.class
)
Additionally, please, see the related question: java - Jackson - #JsonTypeInfo property is being mapped as null?.
Data classes: Implemented toString() method
(Omitted.)
Main: Updated to use root data class
Please, note that I have corrected the JSON document: added the missing comma after "type": "type1".
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
public static void main(String... args) throws JsonProcessingException {
final String jsonDocumentString =
"""
{
"data": [{
"id": "id1",
"type": "type1",
"name": "John"
},
{
"id": "id2",
"type": "type2",
"name": "Rebecca"
},
{
"id": "id3",
"type": "unknown",
"name": "Peter"
}]
}
""";
final ObjectMapper mapper = new ObjectMapper();
final RootData rootData = mapper.readValue(jsonDocumentString, RootData.class);
System.out.println(rootData);
}
}
The program completes successfully, i.e. without an exception being thrown.
The program outputs:
RootData[data=[Type1Data[id='id1', type='type1', name='John'], Type2Data[id='id2', type='type2', name='Rebecca'], AbstractData[id='id3', type='unknown', name='Peter']]]
The actual result (output) is the same as the expected result.

Using Jackson how to map JSONs to objects when it contains an object list

Here is my JSON Payload
{
"allEnvs": ["qa", "dev", "prestaging"],
"env": "qa",
"envUrls": [{
"qa": {
"cutomeUrl": "testUrl",
"adminUrl": "",
"webUrl": "https://test.try.val",
"salesUrl": ""
},
"dev": {
"cutomeUrl": "testUrl",
"webUrl": "",
"salesUrl": ""
},
"prestaging": {
"cutomeUrl": "testUrl",
"webUrl": "",
"salesUrl": ""
}
}],
"isCommonUsers": "true",
"commonUsers":[ {
"teacher": {
"fName": "test",
"lName": "test"
},
"student": {
"fName": "test",
"lName": "test"
},
"ta": {
"fName": "test",
"lName": "test"
}
}],
"commonCodes": ["test1", "test2", "test3"]
}
I would like to know how to map 'envUrls', 'commonUsers' for my 'Conf.class'
ObjectMapper mapper = new ObjectMapper();
CommonConf cnf = mapper.readValue( new File("src/main/resources/configs/config.json"), Conf.class);
envUrls and commonUsers properties can be represented by List<Map<String, PojoX>> type, where PojoX is EnvUrls or User from below model:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Data;
import lombok.ToString;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
public class CommonConfApp {
public static void main(String[] args) throws IOException {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = JsonMapper.builder().build();
System.out.println(mapper.readValue(jsonFile, CommonConf.class));
}
}
#Data
#ToString
class CommonConf {
private List<String> allEnvs;
private String env;
private List<Map<String, EnvUrls>> envUrls;
private String isCommonUsers;
private List<Map<String, User>> commonUsers;
private List<String> commonCodes;
}
#Data
#ToString
class EnvUrls {
private String cutomeUrl;
private String adminUrl;
private String webUrl;
private String salesUrl;
}
#Data
#ToString
class User {
#JsonProperty("fName")
private String fName;
#JsonProperty("lName")
private String lName;
}
Lombok is used for removing boilerplate code. Above app prints:
CommonConf(allEnvs=[qa, dev, prestaging], env=qa, envUrls=[{qa=EnvUrls(cutomeUrl=testUrl, adminUrl=, webUrl=https://test.try.val, salesUrl=), dev=EnvUrls(cutomeUrl=testUrl, adminUrl=null, webUrl=, salesUrl=), prestaging=EnvUrls(cutomeUrl=testUrl, adminUrl=null, webUrl=, salesUrl=)}], isCommonUsers=true, commonUsers=[{teacher=User(fName=test, lName=test), student=User(fName=test, lName=test), ta=User(fName=test, lName=test)}], commonCodes=[test1, test2, test3])
You can annotate your class Conf with following:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Conf {
...
}
It ignores unknown properties while parsing JSON
Documention: JsonIgnoreProperties

Jackson parsing error: exception org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "Results"

There's a few topics like this, however I've read them all and still no luck.
I have a class to which I've made to deserialize some JSON responses from a web service. In short, I've spent too much time looking at this and I'm hoping someone can pick out the error of my ways. As per title, I'm using the Jackson libs.
Snippet of the class below:
final class ContentManagerResponse implements Serializable {
#JsonProperty("Results")
private List<OrgSearchResult> results = null;
#JsonProperty("PropertiesAndFields")
private PropertiesAndFields propertiesAndFields;
#JsonProperty("TotalResults")
private Integer totalResults;
#JsonProperty("CountStringEx")
private String countStringEx;
#JsonProperty("MinimumCount")
private Integer minimumCount;
#JsonProperty("Count")
private Integer count;
#JsonProperty("HasMoreItems")
private Boolean hasMoreItems;
#JsonProperty("SearchTitle")
private String searchTitle;
#JsonProperty("HitHighlightString")
private String hitHighlightString;
#JsonProperty("TrimType")
private String trimType;
#JsonProperty("ResponseStatus")
private ResponseStatus responseStatus;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("Results")
public List<OrgSearchResult> getResults() {
return results;
}
#JsonProperty("Results")
public void setResults(List<OrgSearchResult> results) {
this.results = results;
}
//additional getters and setters.
As said, Results is the property which seems to be having the error.
The JSON response is below.
{
"Results": [
{
"TrimType": "Location",
"Uri": 1684
}
],
"PropertiesAndFields": {},
"TotalResults": 1,
"CountStringEx": "1 Location",
"MinimumCount": 1,
"Count": 0,
"HasMoreItems": false,
"SearchTitle": "Locations - type:Organization and id:24221",
"HitHighlightString": "",
"TrimType": "Location",
"ResponseStatus": {}
}
I'm using the same class to deserialize the following response and it works:
{
"Results": [
{
"LocationIsWithin": {
"Value": true
},
"LocationSortName": {
"Value": "GW_POS_3"
},
"LocationTypeOfLocation": {
"Value": "Position",
"StringValue": "Position"
},
"LocationUserType": {
"Value": "RecordsWorker",
"StringValue": "Records Co-ordinator"
},
"TrimType": "Location",
"Uri": 64092
}
],
"PropertiesAndFields": {},
"TotalResults": 1,
"MinimumCount": 0,
"Count": 0,
"HasMoreItems": false,
"TrimType": "Location",
"ResponseStatus": {}
}
Is the error message just misleading? The structure is identical aside from the second (working) payload not having some of the fields present in the class. I'd expect this one to error if anything.
For what its worth I've also included the OrgSearchResult class below:
final class OrgSearchResult implements Serializable {
#JsonProperty("TrimType") private String trimType;
#JsonProperty("Uri") private String uri;
#JsonIgnore private Map<String, Object> additionalProperties = new HashMap<String, Object>();
//getters and setters
A lot of troubleshooting. I've even tried to use ignore properties can't seem to get them to work.
Full error:
org.codehaus.jackson.map.exc.UnrecognizedPropertyException:
Unrecognized field "Results" (Class
sailpoint.doet.contentmanager.ContentManagerResponse), not marked as
ignorable at [Source: java.io.StringReader#5c6648b0; line: 1, column:
13] (through reference chain:
sailpoint.doet.contentmanager.ContentManagerResponse["Results"])
You can improve readability of POJO class by using PropertyNamingStrategy.UPPER_CAMEL_CASE strategy. Also, you can use JsonAnySetter annotation to read all extra properties. Below example shows how model could look like:
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class JsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.UPPER_CAMEL_CASE);
System.out.println(mapper.readValue(jsonFile, ContentManagerResponse.class));
}
}
class ContentManagerResponse {
private List<OrgSearchResult> results;
private Map<String, Object> propertiesAndFields;
private Integer totalResults;
private String countStringEx;
private Integer minimumCount;
private Integer count;
private Boolean hasMoreItems;
private String searchTitle;
private String hitHighlightString;
private String trimType;
private Map<String, Object> responseStatus;
// getters, setters, toString
}
class OrgSearchResult {
private String trimType;
private String uri;
private Map<String, Object> additionalProperties = new HashMap<>();
#JsonAnySetter
public void additionalProperties(String name, Object value) {
additionalProperties.put(name, value);
}
// getters, setters, toString
}
For first JSON payload above code prints:
ContentManagerResponse{results=[OrgSearchResult{trimType='Location', uri='1684', additionalProperties={}}], propertiesAndFields={}, totalResults=1, countStringEx='1 Location', minimumCount=1, count=0, hasMoreItems=false, searchTitle='Locations - type:Organization and id:24221', hitHighlightString='', trimType='Location', responseStatus='{}'}
For second JSON payload above code prints:
ContentManagerResponse{results=[OrgSearchResult{trimType='Location', uri='64092', additionalProperties={LocationSortName={Value=GW_POS_3}, LocationUserType={Value=RecordsWorker, StringValue=Records Co-ordinator}, LocationIsWithin={Value=true}, LocationTypeOfLocation={Value=Position, StringValue=Position}}}], propertiesAndFields={}, totalResults=1, countStringEx='null', minimumCount=0, count=0, hasMoreItems=false, searchTitle='null', hitHighlightString='null', trimType='Location', responseStatus='{}'}
You do not need to implement Serializable interface.

Jackson, howto deserialize fields with custom name?

I try to deserialize Jira issues from the REST API into an object. Thats quite straight forward. Where I struggle is mapping a custom field in Jira onto a property. I've tried using a custom deserializer but it does not "kick in".
This is how the Json from the REST call looks like:
(some parts stripped)
{
"expand": "renderedFields,names,schema,...",
"id": "53899",
"key": "DPT-12",
"fields": {
"issuetype": {
"id": "10001",
"name": "Story",
"subtask": false
},
"timespent": null,
"project": {
"id": "10823",
"key": "DPT"
},
"fixVersions": [],
"customfield_10111": null,
"aggregatetimespent": null,
"resolution": null,
"customfield_10112": null,
"customfield_10700": [
"entwicklung-w"
],
"customfield_10304": null,
"resolutiondate": null,
"lastViewed": "2017-04-04T14:34:19.868+0200",
"created": "2017-02-02T12:01:31.443+0100",
"priority": {
"name": "Schwer",
"id": "10001"
},
"assignee": {
"displayName": "me :-)"
},
"updated": "2017-04-04T14:34:19.710+0200",
"status": {
"iconUrl": "https://jira.mobi.ch/",
"name": "Backlog",
"statusCategory": {
"name": "Aufgaben"
}
},
"summary": "Ereignisse in rocket Chat schreiben",
"creator": {
"displayName": "me :-)"
},
"reporter": {
"displayName": "me :-)"
}
}
}
The custom field name is configured in my application ("customfield_10700") and I want to map it on the property:
private Set<String> deploymentEnvironments;
So here are the relevant Dto's and the test class (getters and setter stripped here).
Test:
import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
import static org.hamcrest.collection.IsEmptyCollection.empty;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Set;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.junit.Test;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
public class IssueFieldsWithDeserializerTest {
#Test
public void testJiraResponseDeserializer() throws IOException, URISyntaxException {
// arrange
String deploymentEnvsKey = "customfield_10700";
String json = new String(Files.readAllBytes(Paths.get(getClass().getClassLoader().getResource("jira-example-issue-with-customfield-poc.json").toURI())));
ObjectMapper mapper = new ObjectMapper();
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
SimpleModule module = new SimpleModule();
module.addDeserializer(Set.class, new CustomFieldDeserializer(deploymentEnvsKey));
mapper.registerModule(module);
// act
IssueResponsePoc issue = mapper.readValue(json, IssueResponsePoc.class);
// assert
assertThat("issue is not null", issue, is(not(nullValue())));
assertThat("fields are not null", issue.getFields(), is(not(nullValue())));
assertThat("custom field is not null", issue.getFields().getDeploymentEnvironments(), is(not(nullValue())));
assertThat("custom field is not empty", issue.getFields().getDeploymentEnvironments(), is(not(empty())));
assertThat("custom field has one value", issue.getFields().getDeploymentEnvironments(), hasSize(1));
}
}
IssueResponsePoc class:
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
public class IssueResponsePoc implements Serializable {
#JsonProperty private String id;
#JsonProperty private String key;
#JsonProperty private IssueFieldsPoc fields;
}
Interesting class: IssueFieldsPoc
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.annotation.JsonProperty;
public class IssueFieldsPoc implements Serializable {
#JsonProperty private String summary;
#JsonProperty private IssueType issuetype;
#JsonProperty private IssueUser creator;
#JsonProperty private Date created;
#JsonProperty private IssueUser reporter;
#JsonProperty private IssuePriority priority;
#JsonProperty private IssueResolution resolution;
#JsonProperty private List<String> labels;
#JsonProperty private Date resolutiondate;
#JsonProperty private IssueUser assignee;
#JsonProperty private Date updated;
#JsonProperty private IssueStatus status;
#JsonDeserialize private Set<String> deploymentEnvironments;
// #JsonDeserialize(using = CustomFieldDeserializer.class) private Set<String> deploymentEnvironments;
public Set<String> getDeploymentEnvironments() {
return deploymentEnvironments;
}
public void setDeploymentEnvironments(Set<String> deploymentEnvironments) {
this.deploymentEnvironments = deploymentEnvironments;
}
}
My deserializer:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
public class CustomFieldDeserializer extends StdDeserializer<Set<String>> {
private final String customFieldName;
public CustomFieldDeserializer(String customFieldName) {
super((Class<?>) null);
this.customFieldName = customFieldName;
}
#Override
public Set<String> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
System.out.println("deserializer started!");
return null;
}
#Override
public Collection<Object> getKnownPropertyNames() {
return Collections.singletonList(customFieldName);
}
}
I tried registering a custom deserializer but it does not start, I suspect its ignored because jackson cannot identify the field name. Adding the "getKnownPropertyNames" method did not help. Since I need to put the jira custom field name (I read it from a configuration) somewhere I tried to put it into the deserializer. Using the jackson annotation #JsonDeserialize.
I also tried wrapping it into another class and not using Set directly to have a stronger typing. No luck either.
I also tried configuring the deserializer within the annotation but that requires a default constructor and I can no longer configure the jira custom field name.
The current solution uses the #JsonAnySetter annotation:
#JsonAnySetter
public void setCustomProperty(String name, Object value) {
if(StringUtils.startsWith(name, "customfield_")) {
this.customFields.put(name, value);
}
}
But I would prefer having that logic within the deserializer.
Is there a way to help jackson when to start the deserializer (since it knows the property name) for this dynamic property name?
Update:
Registered the module to the mapper.
As suggested in the answers adding the exact property name to the field:
#JsonProperty("customfield_10700")
#JsonDeserialize
private Set<String> deploymentEnvironments;
will allow the deserializer to start. But as mentioned above that is a configurable value I cannot put (or I dont want to) directly in the mapping code.
I think your issue can be resolved by setting #JsonProperty("customfield_10700") to the field deploymentEnvironments as shown below. You don't need a custom deserializer in this case.
public class IssueFieldsPoc implements Serializable {
#JsonProperty private String summary;
#JsonProperty private Date created;
#JsonProperty private List<String> labels;
#JsonProperty private Date resolutiondate;
#JsonProperty private Date updated;
#JsonProperty("customfield_10700")
private Set<String> deploymentEnvironments;
Well, if I understand right, you need to transform json to java object.
If you want that class ignore unknown properties you need add #JsonIgnoreProperties(ignoreUnknown = true) to your classes which must ignore (IssueResponsePoc only or IssueFieldsPoc too).
In #JsonProperty(value = <name_of_property_in_json>) will allow you to use any name for your field in java class.
If you repeat nested levels of json by java classes with corresponding annotations (#JsonProperty, #JsonIgnore and so on) you don't need to use deserializer an whole.
And if you want to process unknown fields in your classes, you can use #JsonAnySetter for this purposes

Categories