I am trying to deserialise following json into Java object but it is complaining that it is not able to recognise the accesslevel property .Please see below:
{
"Role1": [
{
"path": "/1_order/1_general/customer.comp.json",
"accesslevel": "ENABLED"
},
{
"path": "/1_order/1_general/CustomerComponent.json",
"accesslevel": "DISABLED"
},
{
"path": "/2_help/DummyComponent.json",
"accesslevel": "ENABLED"
}
]
}
Java object looks like:
public class AccessLevelConfigWrapper {
HashMap<String, List<AccessLevelDetails>> listOfRoles;
public AccessLevelConfigWrapper() {
}
public HashMap<String, List<AccessLevelDetails>> getListOfRoles() {
return listOfRoles;
}
public void setListOfRoles(HashMap<String, List<AccessLevelDetails>> listOfRoles) {
this.listOfRoles = listOfRoles;
}
}
AccessLevelDetails:
public class AccessLevelDetails {
#JsonProperty
private String accessLevel;
#JsonProperty
private String path;
public String getAccessLevel() {
return accessLevel;
}
public void setAccessLevel(String accessLevel) {
this.accessLevel = accessLevel;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
This is how i am trying to deserialise it :
TypeReference<HashMap<String, List<AccessLevelDetails>>> typeRef = new TypeReference<HashMap<String, List<AccessLevelDetails>>>() {
};
this.accessLevelConfigWrapper = new AccessLevelConfigWrapper();
this.accessLevelConfigWrapper.setListOfRoles(
(new ObjectMapper().readValue(JSONObject.valueToString(this.parentConfigWithPaths), typeRef)));
And i am getting following exception:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "accesslevel" (class com.gatcbiotech.blueberry.gateway.authorization.model.AccessLevelDetails), not marked as ignorable (2 known properties: "accessLevel", "path"])
at [Source: {"CN=it-soft,CN=Groups,DC=intern,DC=gatc-biotech,DC=com":[{"path":"/1_order/1_general/customer.comp.json","accesslevel":"ENABLED"},{"path":"/1_order/1_general/CustomerComponent.json","accesslevel":"DISABLED"},{"path":"/2_help/DummyComponent.json","accesslevel":"ENABLED"}]}; line: 1, column: 122] (through reference chain: java.util.HashMap["CN=it-soft,CN=Groups,DC=intern,DC=gatc-biotech,DC=com"]->java.util.ArrayList[0]->com.gatcbiotech.blueberry.gateway.authorization.model.AccessLevelDetails["accesslevel"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:51)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty(DeserializationContext.java:744)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:915)
at ....
Fix a typo (accessLevel vs accesslevel). JSON has accesslevel, but in annotation you set accessLevel. They should match, because jackson is case-sensitive when parsing JSON keys.
Related
I am trying to parse the following JSON to POJO, specifically the payload I want to extract as String[] or List of String without losing the JSON format.
{
"payLoad": [
{
"id": 1,
"userName": null,
"arName": "A1",
"areas": []
},
{
"id": 2,
"userName": "alpha2",
"arName": "A2",
"areas": []
}
],
"count": 2,
"respCode": 200
}
Here is the POJO that I am using -
public class Response {
#JsonProperty("count")
private int totalCount;
#JsonProperty("respCode")
private int responseCode;
#JsonProperty("payLoad")
#JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private String[] transactionsList;
public String[] getTransactionsList() {
return transactionsList;
}
public void setTransactionsList(String[] transactionsList) {
this.transactionsList = transactionsList;
}
..
}
This is method I am using with springboot to parse it automatically to
public void transactionsReceived() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
Response responseRcvd = objectMapper.readValue(jsonString, Response.class);
}
Here is an error I am getting -
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `[Ljava.lang.String;` from Object value (token `JsonToken.START_OBJECT`)
at [Source: (String)"{"payLoad": [{"id": 1,"userName": null,"arName": "A1","areas": []},{"id": 2,"userName": "alpha2","arName": "A2","areas": []}],"count": 2,"respCode": 200}"; line: 1, column: 14] (through reference chain: com.example.demo.model.Response["payLoad"]->java.lang.Object[][0])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1741)..
You can write custom deserializer:
public class JsonObjectListDeserializer extends StdDeserializer<List<String>> {
public JsonObjectListDeserializer() {
super(List.class);
}
#Override
public List<String> deserialize(JsonParser parser, DeserializationContext context) throws IOException, JacksonException {
JsonNode node = parser.getCodec().readTree(parser);
List<String> result = new ArrayList<>();
if (node.isArray()) {
for (JsonNode element : node) {
result.add(element.toString());
}
} else if (node.isObject()) {
result.add(node.toString());
} else {
//maybe nothing?
}
return result;
}
}
JsonNode.toString() returns json representation of the node, like this you revert the node back to json to save in list.
Then register the deserializer only for this particular field.
public static class Response {
#JsonProperty("count")
private int totalCount;
#JsonProperty("respCode")
private int responseCode;
#JsonProperty("payLoad")
#JsonDeserialize(using = JsonObjectListDeserializer.class)
private List<String> transactionsList;
//getters, setters, etc.
}
JSON Response from API :
{
"result":[
{
"ResultType":"SUCCESS"
}
]
}
After Converting to ResultClass.class :
{
"result":[
{
"resultType":null
}
]
}
Expected Output After Converting to ResultClass.class :
{
"result":[
{
"resultType":"SUCCESS"
}
]
}
I am integrating with third party API.I want to change property name while deserializing .I have tried #JsonProperty on filed getter and setter.But the value is not reflected in field resultType.
ResultClass.java
#JsonProperty("result")
List<TestClass> result = new ArrayList<>();
public List<TestClass> getResult() {
return result;
}
public void setResult(List<TestClass> result) {
this.result = result;
}
TestClass.java
#JsonProperty("ResultType")
private String resultType;
public String getResultType() {
return resultType;
}
public void setResultType(String resultType) {
this.resultType = resultType;
}
Note : I have tried JsonObject and it is working fine.I am using HttpClient and HttpResponse for making request.Jackson Version : 2.5.0
2 Solutions are available:
1. Make case-insensitive deserializing
Add this feature on your object mapper:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
2. Serialize and deserialize with different property names
To change the name of the property ResultType to resultType, you should rather use both #JsonGetter and #JsonSetter:
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonSetter;
public class TestClass {
private String resultType;
#JsonGetter("resultType")
public String getResultType() {
return resultType;
}
#JsonSetter("ResultType")
public void setResultType(String resultType) {
this.resultType = resultType;
}
}
In our project we parse JSON with Jackson. We set field saved by field channelId. Problem is that channelId field is parsed later than saved. So at the time we want to set field saved field channelId is null. How we can set field dependency in JSON deserialization, so field saved will be set after channelId?
This is part of our JSON data:
"message":{
"data":{
"text":"Some text"
},
"saved_by":[
2715,
1234
],
"some_boolean_field":false,
"channel_id":8162
}
This is our entity class:
#JsonIgnoreProperties(ignoreUnknown = true)
#org.parceler.Parcel(org.parceler.Parcel.Serialization.BEAN)
public class Message {
#JsonProperty("channel_id")
protected long channelId;
protected boolean saved;
#JsonSetter("saved_by")
public void setSavedBy(Set<Long> savedBy) {
saved = savedBy.contains(getUserIdByChannelId(channelId));
}
public long getChannelId() {
return channelId;
}
public void setChannelId(long channelId) {
this.channelId = channelId;
}
public boolean isSaved() {
return saved;
}
public void setSaved(boolean saved) {
this.saved = saved;
}
public void setData(JsonNode data) throws JsonProcessingException {
JsonNode textNode = data.get("text");
text = textNode != null ? textNode.asText() : "";
components = new ArrayList<>();
JsonNode mediaNode = data.get("media");
if (mediaNode != null) {
MessageComponent[] parsedComponents = AppSession.getInstance().getObjectMapper().treeToValue(mediaNode, MessageComponent[].class);
List<MessageComponent> components = Arrays.asList(parsedComponents).subList(0, parsedComponents.length < 4 ? parsedComponents.length : 4);
this.components.addAll(components);
}
mediaCount = components.size();
}
}
Full JSON:
{
"data":{
"serial":66,
"updated_entity":"bookmark",
"bookmark":{
"message":{
"data":{
"text":"hello"
},
"counted_serial":748,
"saved_by":[
26526,
27758
],
"type":"UserMessage",
"is_reviewed":false,
"channel_id":8128,
"id":2841531,
"replied_message_data":null,
"is_blocked":false,
"is_deleted":false,
"updated_at":"2016-11-21T05:59:52.471Z",
"spam_reported_by":[
],
"created_at":"2016-11-19T15:40:17.027Z",
"uuid":"0b6ba58e-f5e1-4ee5-a9da-041dfc2c85cd",
"liked_by":[
],
"user":{
"last_name":"M",
"id":4537,
"first_name":"John",
"is_deleted":false,
"avatar_thumb":"https:\/\/cdn.site.org\/uploads\/99ef4d68-6eaf-4ba6-aafa-74d1cf895d71\/thumb.jpg"
},
"serial":934
},
"id":6931,
"created_at":"2016-11-21T05:59:52.459Z",
"is_deleted":false,
"updated_at":"2016-11-21T05:59:52.459Z"
}
},
"type":"action_performed"
}
It's a bit hackish, but by making the Message class its own deserialization-builder, you get a kind of "ready for bean creation"-event in which you have access to all of the properties.
My suggestion is that you try the following :
#JsonDeserialize(builder = Message.class)
public class Message {
...
#JsonSetter("saved_by")
public void setSavedBy(Set<Long> savedBy) {
// Merely store the value for later use.
this.savedBy = savedBy;
}
...
public Message build() {
// Calculate value of "saved" field.
this.saved = this.savedBy.contains(getUserIdByChannelId(this.channelId));
return this;
}
// Handling the added challenge.
#JsonProperty("data")
public void setData(JsonNode data) throws JsonProcessingException {
...
}
}
The above takes advantage of the default settings of the JsonPOJOBuilder annotation, namely that the default value for buildMethodName is build.
My Json looks something like (and its unmodifiable)
{
....
"Sale": [
{ "SaleLines": {
"SaleLine": [
{
"unitPrice": "190",
"unitQuantity": "1"
}
],
"calcDiscount": "0",
"calcSubtotal": "500"
}
} ]
}
The java POJO code looks like
public static class SaleLines {
#JsonProperty("SaleLine")
private ArrayList<SaleLine> saleLine;
public ArrayList<SaleLine> getSaleLine() { return saleLine; }
public void setSaleLine(ArrayList<SaleLine> saleLine) { this.saleLine = saleLine; }
}
public static class SaleLine {
#JsonProperty("itemID")
private String itemId; //line_item_nk
#JsonProperty("unitPrice")
private String unitPrice;
....
}
#JsonPropertyOrder({"total", "calcSubTotal", "calcDiscount"})
public static class Sale {
private String saleTotal, calcSubtotal, calcDiscount;
private int salesValueWOVat;
#JsonProperty("SaleLines")
SaleLines saleLine;
#JsonCreator
public Sale (#JsonProperty("total")String saleTotal,
#JsonProperty("calcSubtotal")String calcSubtotal,
#JsonProperty("calcDiscount")String calcDiscount,
#JsonProperty("SaleLines")SaleLines saleLine,
) {
this.saleTotal = saleTotal;
this.calcSubtotal = calcSubtotal;
this.calcDiscount = calcDiscount;
this.saleLine = saleLine;
setSalesValueWOVat();
}
// getter and setters
}
#SuppressWarnings({ "rawtypes" })
public static <E, T extends Collection> T readFromJsonAndFillType (
String json,
Modules module,
Class <T> collectionType,
Class <E> elementType)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
TypeFactory tf = objMapper.getTypeFactory();
JsonNode node = objMapper.readTree(json).get(module.jsonFieldName);
return objMapper.readValue(node.toString(),
tf.constructCollectionType(collectionType, elementType));
}
In main
ArrayList<Sale> saleList = readFromJsonAndFillType(
saleJSON,
Modules.SALE,
ArrayList.class,
Sale.class);
for (Sale sale: saleList) {
System.out.println(sale.getSaleLines().getSaleLine().size()); //ERROR Null Pointer Exception
System.out.println(sale.toString());
}
So, the problem is that the SaleLine does not get populated as expected
It is possible that your JSON is invalid; e.g. there are commas missing in the latest version in your Question.
If the problem is that your JSON is syntactically invalid, then you will either need to hack the JSON before you parse it or hack the parser to accept invalid JSON.
On the other hand, it is possible that some of your JSON records are missing the SaleLine or SaleLines attributes or have a null instead of one of the values. If that is possible, add some null tests ... and reject the record or cope with the missing data.
My Json looks something like (and its unmodifiable)
{
....
"Sale": [
"SaleLines": {
"SaleLine": [
{
"Item": {
"Prices": {
"ItemPrice": [
{
"amount": "100",
"useType": "Default"
},
{
"amount": "100",
"useType": "MSRP"
}
]
},
}
......
......
}
]
"calcDiscount": "0",
"calcSubtotal": "500",
}
]
}
The java POJO code looks like
public static class SaleLines {
#JsonProperty("SaleLine")
private SaleLineObject[] saleLineObject;
public SaleLineObject[] getSaleLineObject() { return saleLineObject; }
public void setSaleLineObject(SaleLineObject[] saleLineObject) { this.saleLineObject = saleLineObject; }
}
public static class SaleLineObject {
private SaleLine saleLine;
public SaleLine getSaleLine() {
return saleLine;
}
public void setSaleLine(SaleLine saleLine) {
this.saleLine = saleLine;
}
}
public static class SaleLine {
#JsonProperty("itemID")
private String itemId; //line_item_nk
#JsonProperty("unitPrice")
private String unitPrice;
....
}
#JsonPropertyOrder({"total", "calcSubTotal", "calcDiscount"})
public static class Sale {
private String saleTotal, calcSubtotal, calcDiscount;
private int salesValueWOVat;
#JsonProperty("SaleLines")
SaleLines saleLine;
#JsonCreator
public Sale (#JsonProperty("total")String saleTotal,
#JsonProperty("calcSubtotal")String calcSubtotal,
#JsonProperty("calcDiscount")String calcDiscount,
#JsonProperty("SaleLines")SaleLines saleLine,
) {
this.saleTotal = saleTotal;
this.calcSubtotal = calcSubtotal;
this.calcDiscount = calcDiscount;
this.saleLine = saleLine;
setSalesValueWOVat();
}
// getter and setters
}
#SuppressWarnings({ "rawtypes" })
public static <E, T extends Collection> T readFromJsonAndFillType (
String json,
Modules module,
Class <T> collectionType,
Class <E> elementType)
throws JsonParseException, JsonMappingException, IOException {
ObjectMapper objMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
TypeFactory tf = objMapper.getTypeFactory();
JsonNode node = objMapper.readTree(json).get(module.jsonFieldName);
return objMapper.readValue(node.toString(),
tf.constructCollectionType(collectionType, elementType));
}
In main
ArrayList<Sale> saleList = readFromJsonAndFillType(
saleJSON,
Modules.SALE,
ArrayList.class,
Sale.class);
for (Sale sale: saleList) {
System.out.println(sale.toString());
}
I know this question has been asked multiple times and even I took help from for eg
Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
But still I cannot get through this error
I know this question has been asked multiple times & everyone getting resolved there problems with different ways. Whenever you find "Can not deserialized instance of out of START_OBJECT token". it's generally occur when you trying to get object which is not actually same in json format (means json starting object is different not as you guys are converting).
For Ex:- Json returning first object is Boolean but unfortunately you are converting is to List<Object> then you will having this error.
I would suggest to have a look to read format using below code than convert it as per the object returning.
ObjectMapper objectMapper = new ObjectMapper();
Map<?,?> empMap = objectMapper.readValue(new FileInputStream("employee.json"),Map.class);
for (Map.Entry<?,?> entry : empMap.entrySet())
{
System.out.println("\n----------------------------\n"+entry.getKey() + "=" + entry.getValue()+"\n");
}
Get the key & convert the value as per the object returning.
For reference:- https://dzone.com/articles/processing-json-with-jackson