{
"response": [
{
"id": "1",
"name": "xx"
},
{
"id": "2",
"name": "yy"
}
],
"errorMsg": "",
"code": 0
}
How to parse "response" alone using jackson parser. I am getting error as
Unrecognized field "errorMsg", not marked as ignorable.
My model class Response.java
public class Response {
#JsonProperty("id")
private Integer id;
#JsonProperty("name")
private String name;
}
Your data model is a bit incomplete and this is what Jackson is pointing out.
To improve the situation you should map more fields.
public class Response {
#JsonProperty("id")
private Integer id;
#JsonProperty("name")
private String name;
// getter/setter...
}
public class Data {
#JsonProperty("response")
private List<Response> response;
#JsonProperty("errorMsg")
private String errorMsg;
#JsonProperty("code")
private int code;
// getter/setter...
}
You can either create a parent object and use #JsonIgnoreProperties. Alternatievly you could get the node and convert it to response object using ObjectMapper's convertValue() method like
try {
String json = "{\"response\":[{\"id\":\"1\",\"name\":\"xx\"},{\"id\":\"2\",\"name\":\"yy\"}],\"errorMsg\":\"\",\"code\":0}";
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(json);
List<Response> responses = mapper.convertValue(node.findValues("response").get(0), new TypeReference<List<Response>>() {});
System.out.println(responses);
} catch (JsonProcessingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Related
I am trying to map my incoming json payload to an arraylist of my model class.
I have a solution but its unintuitive.
I try to do this but get compilation errors-
ObjectMapper mapper = new ObjectMapper();
ArrayList<ModelClass> = mapper.readValue(items, RoleAttribute.class);
FYI I am trying to save this data in a Mongo collection.
Controller-
#PostMapping(value="/resource", consumes="application/json")
public Iterable<ModeClass> createResources(#RequestBody JSONObject requestBody ) throws JsonParseException, JsonMappingException, IOException {
System.out.println(requestBody.getClass());
return serviceImpl.saveResources(requestBody);
}
Model class-
#Data
#AllArgsConstructor
#Document(collection="collection-name")
public
class ModelClass{
#Field
private String ID;
#Field
private String description;
}
The payload is coming in the following format-
{
"data": [
{
"ID": "1",
"description": "desc1"
},
{
"ID": "2",
"description": "desc2"
},
{
"ID": "3",
"description": "desc3"
},
{
"ID": "4",
"description": "desc4"
}
....
]
}
I know I should be using jackson but I can't seem to figure this out. Do I need to change my POJO? Do I need to create custom Jackson config?
You can do it with json annotation. I also notice that your values are represented as data in json so that also needs to be taken care of. Look at below code. That will solve your problem.
import com.fasterxml.jackson.annotation.JsonProperty;
#Data
#AllArgsConstructor
#Document(collection="collection-name")
public class ModelClass{
#Field
#JsonProperty("ID")
private String classID;
#Field
#JsonProperty("description")
private String classDescription;
public String getClassID() {
return classID;
}
public void setClassID(String classID) {
this.classID = classID;
}
public String getClassDescription() {
return classDescription;
}
public void setClassDescription(String classDescription) {
this.classDescription = classDescription;
}
}
And wrapper Data class as below
class Data {
ModelClass[] data;
public ModelClass[] getData() {
return data;
}
public void setData(ModelClass[] data) {
this.data = data;
}
}
And json conversion code as below
ObjectMapper mapper = new ObjectMapper();
// json is your incoming json as a string. You can put inputstream also
Data values = mapper.readValue(json, Data.class);
System.out.println(values.getData().length);
System.out.println(values.getData()[0].getClassID());
You would need a container class for the data field, something like:
#Data
#Document(collection="collection-name")
public class DataClass{
private List<ModelClass> data;
}
Doing it via Jackson should be automatic this way, in controller:
public Iterable<ModeClass> createResources(#RequestBody DataClass requestBody ) {
I have created customer json file as below:
[
{
"firstName": “test”,
"lastName": “temp”,
"age": 35,
"emailAddress": “test#Gmail.com",
"address": {
"streetAddress": “test testing“,
"city": “city”,
"postCode": “12343546”,
"state": “state”,
"country": “cy”,
"county": “abc”
},
"phoneNumber": {
"home": "012345678",
"mob": "0987654321"
}
},
{
"firstName": “tug”,
"lastName": “kjk”,
"age": 35,
"emailAddress": “jhgj#Gmail.com",
"address": {
"streetAddress": “jh hjgjhg ,
"city": “kjhjh”,
"postCode": "122345",
"state": “jhgl”,
"country": “jaj”,
"county": “jhgkg”
},
"phoneNumber": {
"home": "012345678",
"mob": "0987654321"
}
}
]
For the Customer JSON data file, I have created below JSON datareader class:
public class JsonDataReader {
private final String customerFilePath = new ConfigFileReader().getTestDataResourcePath() + "Customer.json";
private List<Customer> customerList;
public JsonDataReader(){
customerList = getCustomerData();
}
private List<Customer> getCustomerData() {
Gson gson = new Gson();
BufferedReader bufferReader = null;
try {
bufferReader = new BufferedReader(new FileReader(customerFilePath));
Customer[] customers = gson.fromJson(bufferReader, Customer[].class);
return Arrays.asList(customers);
}catch(FileNotFoundException e) {
throw new RuntimeException("Json file not found at path : " + customerFilePath);
}finally {
try { if(bufferReader != null) bufferReader.close();}
catch (IOException ignore) {}
}
}
public final Customer getCustomerByName(String customerName){
for(Customer customer : customerList) {
if(customer.firstName.equalsIgnoreCase(customerName)) return customer;
}
return null;
}
}
Created POJO class as below:
public class Customer {
public String firstName;
public String lastName;
public int age;
public String emailAddress;
public Address address;
public PhoneNumber phoneNumber;
public class Address {
public String streetAddress;
public String city;
public String postCode;
public String state;
public String country;
public String county;
}
public class PhoneNumber {
public String home;
public String mob;
}
}
This is working fine so far as there is only one JSON data file, however I will create more JSON data files, so may be I have to create multiple POJOs for each one, but is there any way I can write common generic jsondatareader class for all those JSON files?
A class (or an Object) is a well defined entity. By well defined I mean that its structure is known at compile time, and cannot be changed after that point.
Having to create multiple classes to represent multiple JSON documents is perfectly fine. So if you're worried about the amount of files you'll create, it's a non-problem.
But, if the JSON document structure will keep changing along with every request, there is no point in defining a series of classes. To handle totally dynamic JSON you should stick with what Gson offers you. That is JsonElement and its subclasses.
JsonElement
> JsonArray
> JsonObject
> JsonPrimitive
> JsonNull
That's all what is needed to describe a JSON object.
If that is the case then why not convert JSON into a Map instead of a POJO! If you go POJO route then you will utilizing Jackson or GSon heavily in your code base adding bunch of utility methods to iterate over every resulting JSonArray or JSonelements.
I intend to create a JSON Array with the following structure. The metadata tag is going to constant in all the entries. I am stumped.
[{
"metadata": {
"Value": "String"
},
"name": "String",
"id": "String"
},
{
"metadata": {
"Value": "String"
},
"name": "String",
"id": "String"
}
]
public class yourJsonObject {
private Map<String, String> metadata;
private String name;
private string id;
public yourJsonObject() {
}
public Map<String, String> getMetadata(){
return metadata;
}
public void setMetadata(Map<String, String> metadata){
this.metadata = metadata;
}
public String getName(){
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId(){
return id;
}
public void setId(String id){
this.id = id;
}
}
Then somewhere else you can just do this:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject example = new yourJsonObject(); // have your POJO you want to save
mapper.writeValue(new File("result.json"), example);
To read you can just use:
ObjectMapper mapper = new ObjectMapper(); // create once, reuse
yourJsonObject value = mapper.readValue(new File("data.json"), yourJsonObject .class);
Both snippets are taken from my linked wiki article from jackson themselves.
Jackson should automatically be able to parse this POJO to an equivalent JSON if configured correctly.
Note: Jackson has to be globally registered and has to know about it. Please read the wiki of what you use to know about it... Jackson in 5 Minutes
Else you could just manually build the JSON like Neeraj said.
JSONArray array = new JSONArray(); // Create JSONArray Object
JSONObject jsonObject = new JSONObject(); // Your JSONObject which gets added into array
jsonObject.put("metadata",new MetaDataCustomClass("SomeRandomStringValue"));
jsonObject.put("name", "Neeraj");
jsonObject.put("id", "123");
array.add(jsonObject); // Here you push the jsonObject into Array.
Note: MetaDataCustomClass is just a custom Class having a Value instance variable of type String.
Class MetaDataCustomClass {
private String value;
public MetaDataCustomClass(String value){
this.value = value;
}
}
I am using GSON for the first time. I am trying to deserialise a JSON string into a custom object, but every property of my object is set to null. There are no parsing errors so I think the JSON properties are not mapping to the object?
Here is my code, if anyone could point out where I have gone wrong it would be much appreciated. I have checked everything against tutorial and cannot see the problem. The only thing is that there are more properties in the JSON string than in my object but I hope that does not matter.
JSON string:
{
"_id": "D7D4A7D8219CA25848257C63000A1B50",
"ReportingPerson": "TRAIN2 Ifap",
"InjuredPerson": "TRAIN3 Ifap",
"DateReported": {
"$date": "2014-01-17T00:00:00.000Z"
},
"Company": "test",
"Division": "Learning & Development",
"Site_id": "3CA9AD4E6066388648257B7500047D90",
"Department_id": "724BC4B509E7B61648257363002FD645",
"Area": "Training Room",
"DocNo": "002223",
"CreatedBy": "Ifap TRAIN2",
"DateComposed": {
"$date": "2014-01-17T01:50:23.000Z"
},
"OccurTime": "12:00:00",
"Affiliation": "Employee",
"BriefDescription": "Employee tripped over power lead in computer lab.",
"ThirdPartyInvolvedYN": "No",
"ThirdPartyName": "",
"ThirdPartyAddress": [
""
],
"ThirdPartyTel": "",
"Classification": "Minor Injury",
"Confidential": "",
"ConfidentialMonitors": [
""
],
"IncidentCategory": "2",
"IncidentCategoryPotential": "3",
"ReportableYN": "No",
"ExternalBody": [
""
],
"Authorisor": "",
"WorkSafeConfirmedYN": "No",
"Details": "Fell over cord in computer lab when walking through. Held hand out to brace fall and fell on pinkie finger.",
"Controls": [
"Tape over cord."
],
"Witnesses": [
"No"
],
"Supervisor": "TRAIN1 Ifap",
"IntAuthorisor": "TRAIN3 Ifap",
"IntAuthorisorNext": "",
"AssociatedRisks": {},
"OpenActions": {},
"ClosedActions": {}
}
POJO:
public class Incident {
#SerializedName("_id")
private String _id;
private String docNo;
private String site_id;
private String company;
private String division;
private String department_id;
private Date dateReported;
private String briefDescription;
private String thirdPartyInvolvedYN;
private String supervisor;
private String classification;
private String status;
private String injuredPerson;
private String reportingPerson;
private Date occurDate;
private String occurTime;
//Getters & Setters...
}
Main method:
public Incident convertJSONToBean(String json) {
Incident i = new Incident();
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
Type type = new TypeToken<Incident>(){}.getType();
try {
i = gson.fromJson(json, type);
} catch (JsonSyntaxException e) {
e.printStackTrace();
} catch (JsonIOException e) {
e.printStackTrace();
}
return i;
}
Type is set correctly to Incident.class. But any properties of the resulting Incident object are all null.
I tried commenting out all properties except _id to see if I could get just one to populate but it was still set to null.
In Json format DateComposed & DateReported properties are the Object, You need to create the
either custom model classes for them or write CustomDeserializer class for them.
"DateComposed": { "$date": "2014-01-17T01:50:23.000Z" }
"DateReported": {"$date": "2014-01-17T00:00:00.000Z"}
public class Incident {
#SerializedName("_id")
private String _id;
#SerializedName(value = "ReportingPerson")
// other properties, you need to put #SerializedName on each property
............
// No need to put SerializedName annotation on dateReported & dateComposed
private Date dateReported;
private Date dateComposed;
#SerializedName(value = "ThirdPartyAddress")
private List<String> thirdPartyAddress;
#SerializedName(value = "ConfidentialMonitors")
private List<String> confidentialMonitors;
#SerializedName(value = "ExternalBody")
private List<String> externalBody;
#SerializedName(value = "Controls")
private List<String> controls;
#SerializedName(value = "Witnesses")
private List<String> witnesses;
// getter/setter
....
}
Here is the CustomDeserializer class for Deserializing date properties
public class CustomDeserializer implements JsonDeserializer<Incident> {
#Override
public Incident deserialize(JsonElement json, Type type,
JsonDeserializationContext context) throws JsonParseException {
final JsonObject jsonObject = json.getAsJsonObject();
final Gson gson = new Gson();
// Parse the JsonElement tree here
final Incident incident = gson.fromJson(json, Incident.class);
// getting date properties as string from JsonElement and parse them into date object.
String dateReportedStr = jsonObject.get("DateReported").getAsJsonObject().get("$date").getAsString();
String dateComposedStr = jsonObject.get("DateComposed").getAsJsonObject().get("$date").getAsString();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
try {
// setting date properties in incident object
incident.setDateReported(df.parse(dateReportedStr));
incident.setDateComposed(df.parse(dateComposedStr));
} catch (ParseException e) {
e.printStackTrace();
}
return incident;
}
}
Finally Parse it
final GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Incident.class, new CustomDeserializer());
Gson gson = gsonBuilder.create();
Incident incident = gson.fromJson(Your_JSON_STR, Incident.class);
You have interesting date objects in your json string. Such as;
"DateReported": {
"$date": "2014-01-17T00:00:00.000Z"
}
Which causes a JsonParseException because of your Incident class:
com.google.gson.JsonParseException: The date should be a string value
For your Incident class, Dates at json value should be something like;
"DateReported": "2014-01-17T00:00:00.000Z"
If you don't have an option to change dates at json value, then you should define its custom date holder class:
public class CustomDateHolder {
#SerializedName("$date")
private Date date;
// Getters & Setters...
}
And change those date fields' type to CustomDateHolder;
public class Incident {
#SerializedName("_id")
private String _id;
private String docNo;
private String site_id;
private String company;
private String division;
private String department_id;
private CustomDateHolder dateReported;
private String briefDescription;
private String thirdPartyInvolvedYN;
private String supervisor;
private String classification;
private String status;
private String injuredPerson;
private String reportingPerson;
private CustomDateHolder occurDate;
private String occurTime;
// Getters & Setters...
}
Also modify your GsonBuilder a little bit:
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
gsonBuilder.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
Gson gson = gsonBuilder.create();
This is my JSON:
{
"results": [
{
"user_id": "1",
"item_id": "18630",
"name": "Unnamed Item",
"price": "0",
"description": "",
"created_at": "2014-01-16 15:31:36",
"thumbnail": {
"image50": "http://www.example.com/adsa.jpg",
"image100": "hhttp://www.example.com/adsa.jpg"
},...
Am I doing the deserialization right?
public class ItemListModel {
private String user_id;
private String item_id;
private String name;
private String price;
private String category;
private ArrayList<ThumbnailResponse> thumbnail;
public ItemListModel(){}
// getters
}
public class ThumbnailResponse {
private String image50;
private String image100;
public ThumbnailResponse(){
}
//getters
}
I'm just confused, when do we use ArrayList, Array or List for array or object in the JSON file?
One more thing, do I need to make results as an array too if that's the case?
As you have given
"thumbnail": {
"image50": "http://www.example.com/adsa.jpg",
"image100": "hhttp://www.example.com/adsa.jpg"
}
is not a JsonArray. So you have no need to use ThumbnailResponse as an ArrayList into ItemListModel.
Your Model should be
public class ItemListModel {
private String user_id;
private String item_id;
private String name;
private String price;
private String category;
private ThumbnailResponse thumbnail; // Not array List
public ItemListModel(){}
// getters
}
And
One more thing, do I need to make results as an array too if that's
the case?
Your main data container should be contain ArrayList of ItemListModel. Like below
ArrayList<ItemListModel> results = new ArrayList<ItemListModel>();
[] in json -> array
{} in json -> object or map
in your case
// change
private ArrayList<ThumbnailResponse> thumbnail;
// to
private Map<String,String> thumbnail;
if you want it the way you declared your java object you need to provide a transformer (depends on the framework you are using)
List<ItemListModel > ItemListModel ;
try {
Type listType = new TypeToken<List<ItemListModel >>(){}.getType();
result= (List<ItemListModel >) gson.fromJson(result, listType);
} catch (Exception e) {
Log.e("Parsing exeption", e.getLocalizedMessage(), e);
}
this should work