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
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.
}
I am trying to apply Lifecycle Configurations on S3 bucket. Trying to apply using following JSON:
[{
"id": "tmpdelete",
"status": "Enabled",
"filter": {
"predicate": {
"prefix": "tmp"
}
},
"transitions": [{
"days": "1",
"storageClass": "GLACIER"
}],
"noncurrentVersionTransitions": [{
"days": "1",
"storageClass": "GLACIER"
}],
"expirationInDays": "2",
"noncurrentVersionExpirationInDays": "2",
"expiredObjectDeleteMarker": "true"
}]
When i am trying to map it with Rule[].class it is not working. I am using following code:
String json = above_json;
Rule[] rules = null;
Gson gson = new GsonBuilder().serializeNulls().excludeFieldsWithModifiers(Modifier.FINAL,
Modifier.TRANSIENT, Modifier.STATIC, Modifier.ABSTRACT).create();
rules = gson.fromJson(json, Rule[].class);
try {
amazonS3.setBucketLifecycleConfiguration(bucketName, new BucketLifecycleConfiguration().withRules(rules));
} catch (Exception e) {
throw e;
}
It throws error saying Failed to invoke public com.amazonaws.services.s3.model.lifecycle.LifecycleFilterPredicate() with no args. LifecycleFilterPredicate is an abstract class which implements Serializable and it doesn't have no-args contructor. How to solve this problem.?
Ok, I think I found your problem: when GSON tries to construct the objects from that json string into an actual object (or, in this case, a list of objects), the process fails because when it gets to the filter.predicate bit, it probably tries to do something like this:
LifecycleFilterPredicate predicate = new LifecycleFilterPredicate();
predicate.setPrefix("tmp");
Which doesn't work because LifecycleFilterPredicate doesn't have a public constructor without any arguments, as you've stated.
I think that, unfortunately, your only solution is to parse the JSON in a different way.
UPDATE
You'll need to make use of a GSON TypeAdapter as follows:
class LifecycleFilterPredicateAdapter extends TypeAdapter<LifecycleFilterPredicate>
{
#Override
public LifecycleFilterPredicate read(JsonReader reader)
throws IOException
{
if (reader.peek() == JsonToken.NULL) {
reader.nextNull();
return null;
}
reader.beginObject();
if(!"prefix".equals(reader.nextName()))
{
return null;
}
String prefix = reader.nextString();
LifecyclePrefixPredicate predicate = new LifecyclePrefixPredicate(prefix);
reader.endObject();
return predicate;
}
#Override
public void write(JsonWriter writer, LifecycleFilterPredicate predicate)
throws IOException
{
//nothing here
}
}
...
Gson gson = new GsonBuilder().serializeNulls().excludeFieldsWithModifiers(Modifier.FINAL,
Modifier.TRANSIENT, Modifier.STATIC, Modifier.ABSTRACT)
.registerTypeAdapter(LifecycleFilterPredicate.class, new LifecycleFilterPredicateAdapter()).create();
I've tried it locally and don't get the exception anymore :)
I tried this and it worked for me
public class RuleInstanceCreator implements InstanceCreator<LifecycleFilterPredicate> {
#Override
public LifecycleFilterPredicate createInstance(Type type) {
return new LifecycleFilterPredicate() {
private static final long serialVersionUID = 1L;
#Override
public void accept(LifecyclePredicateVisitor lifecyclePredicateVisitor) {
}
};
}
}
Gson gson = new GsonBuilder()
.registerTypeAdapter(LifecycleFilterPredicate.class, new LifecycleFilterPredicateAdapter()).create();
rules = gson.fromJson(json, Rule[].class);
I am looking to serialize my class using gson but I would like to omit the hashmap name. Is this possible with gson?
I have tried writing my own TypeAdapter but the map name is still written as the parent object.
I have a class which looks like
public class myClass {
#Expose
public Long timestamp;
#Expose
public String id;
#Expose
public HashMap<String, someOtherClass> myMap = new HashMap<>();
#Override
public String toString() {
Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
return gson.toJson(this);
}
}
current output :
{
"timestamp": 1517245340000,
"id": "01",
"myMap": {
"mapKey1": {
"otherClassId": "100", // works as expected
}
"mapKey2": {
"otherClassId": "101", // works as expected
}
}
}
What I am hoping to get :
{
"timestamp": 1517245340000,
"id": "01",
"mapKey1": {
"otherClassId": "100", // works as expected
},
"mapKey2": {
"otherClassId": "100", // works as expected
}
}
Write your own TypeAdapter. See javadoc for example.
Specify it with #JsonAdapter annotation, or register it with GsonBuilder.
#JsonAdapter(MyClassAdapter.class)
public class MyClass {
public Long timestamp;
public String id;
public HashMap<String, SomeOtherClass> myMap = new HashMap<>();
}
public class MyClassAdapter extends TypeAdapter<MyClass> {
#Override public void write(JsonWriter out, MyClass myClass) throws IOException {
// implement the write method
}
#Override public MyClass read(JsonReader in) throws IOException {
// implement the read method
return ...;
}
}
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.
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.