How to use Retrofit2 to deserialize when JsonArray nested to another JsonArray - java

Here is my Json data.
[
{
"id": 280866,
"student_id": 7,
"lesson_date_id": 31476,
"recorded_time": "11:49:55",
"lecturer_id": null,
"status": 12895,
"created_at": "2017-07-31 11:49:55",
"updated_at": null,
"lesson_date": {
"id": 31476,
"lesson_id": 28,
"ldate": "2017-07-31",
"updated_by": 1,
"created_at": "2017-04-19 03:33:43",
"updated_at": null
},
"lecturer": null,
"lesson": {
"id": 28,
"semester": "2",
"module_id": "009521",
"subject_area": "IS PDA",
"catalog_number": "7COMISS",
"class_section": "T03",
"component": "TUT",
"facility": "05-04-0009",
"venue_id": 2,
"weekday": "2",
"start_time": "08:00:00",
"end_time": "12:00:00",
"meeting_pattern": "",
"created_at": "0000-00-00 00:00:00",
"updated_at": "2017-07-10 10:19:51",
"lesson_name": null,
"credit_unit": null
}
},
{
"id": 284077,
"student_id": 6,
"lesson_date_id": 31476,
"recorded_time": "00:00:24",
"lecturer_id": null,
"status": -1,
"created_at": "2017-08-01 00:00:23",
"updated_at": null,
"lesson_date": {
"id": 31476,
"lesson_id": 28,
"ldate": "2017-07-31",
"updated_by": 1,
"created_at": "2017-04-19 03:33:43",
"updated_at": null
},
"lecturer": null,
"lesson": {
"id": 28,
"semester": "2",
"module_id": "009521",
"subject_area": "IS PDA",
"catalog_number": "7COMISS",
"class_section": "T03",
"component": "TUT",
"facility": "05-04-0009",
"venue_id": 2,
"weekday": "2",
"start_time": "08:00:00",
"end_time": "12:00:00",
"meeting_pattern": "",
"created_at": "0000-00-00 00:00:00",
"updated_at": "2017-07-10 10:19:51",
"lesson_name": null,
"credit_unit": null
}
},
{
"id": 284076,
"student_id": 5,
"lesson_date_id": 31476,
"recorded_time": "00:00:24",
"lecturer_id": null,
"status": -1,
"created_at": "2017-08-01 00:00:23",
"updated_at": null,
"lesson_date": {
"id": 31476,
"lesson_id": 28,
"ldate": "2017-07-31",
"updated_by": 1,
"created_at": "2017-04-19 03:33:43",
"updated_at": null
},
"lecturer": null,
"lesson": {
"id": 28,
"semester": "2",
"module_id": "009521",
"subject_area": "IS PDA",
"catalog_number": "7COMISS",
"class_section": "T03",
"component": "TUT",
"facility": "05-04-0009",
"venue_id": 2,
"weekday": "2",
"start_time": "08:00:00",
"end_time": "12:00:00",
"meeting_pattern": "",
"created_at": "0000-00-00 00:00:00",
"updated_at": "2017-07-10 10:19:51",
"lesson_name": null,
"credit_unit": null
}
},
{
"id": 284075,
"student_id": 4,
"lesson_date_id": 31476,
"recorded_time": "00:00:24",
"lecturer_id": null,
"status": -1,
"created_at": "2017-08-01 00:00:23",
"updated_at": null,
"lesson_date": {
"id": 31476,
"lesson_id": 28,
"ldate": "2017-07-31",
"updated_by": 1,
"created_at": "2017-04-19 03:33:43",
"updated_at": null
},
"lecturer": null,
"lesson": {
"id": 28,
"semester": "2",
"module_id": "009521",
"subject_area": "IS PDA",
"catalog_number": "7COMISS",
"class_section": "T03",
"component": "TUT",
"facility": "05-04-0009",
"venue_id": 2,
"weekday": "2",
"start_time": "08:00:00",
"end_time": "12:00:00",
"meeting_pattern": "",
"created_at": "0000-00-00 00:00:00",
"updated_at": "2017-07-10 10:19:51",
"lesson_name": null,
"credit_unit": null
}
},
{
"id": 280865,
"student_id": 2,
"lesson_date_id": 31476,
"recorded_time": "11:49:55",
"lecturer_id": null,
"status": 12895,
"created_at": "2017-07-31 11:49:55",
"updated_at": null,
"lesson_date": {
"id": 31476,
"lesson_id": 28,
"ldate": "2017-07-31",
"updated_by": 1,
"created_at": "2017-04-19 03:33:43",
"updated_at": null
},
"lecturer": null,
"lesson": {
"id": 28,
"semester": "2",
"module_id": "009521",
"subject_area": "IS PDA",
"catalog_number": "7COMISS",
"class_section": "T03",
"component": "TUT",
"facility": "05-04-0009",
"venue_id": 2,
"weekday": "2",
"start_time": "08:00:00",
"end_time": "12:00:00",
"meeting_pattern": "",
"created_at": "0000-00-00 00:00:00",
"updated_at": "2017-07-10 10:19:51",
"lesson_name": null,
"credit_unit": null
}
}
]
I use Retrofit2 and can get the correct response when i don't put the lesson_dateand beacon_lesson in my Model.That's means using Retrofit2 ,i can only get the JsonObject in the specific jsonArray. But when there's another JsonArray lesson_date and beacon_lesson is nested in the JsonArray. But if i use the same method in my Model ,it will have no response, even don't have the error message.
Here is my Model class.
public class TimetableResult {
#SerializedName("id")
#Expose
private String id;
#SerializedName("lesson_id")
#Expose
private String lesson_id;
#SerializedName("lecturer_id")
#Expose
private String lecturer_id;
#SerializedName("lesson")
#Expose
private Lesson lesson;
#SerializedName("venue")
#Expose
private Venue venue;
#SerializedName("lesson_date")
#Expose
private LessonDate lesson_date;
#SerializedName("beaconLesson")
#Expose
private LessonBeacon lessonBeacon;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLesson_id() {
return lesson_id;
}
public void setLesson_id(String lesson_id) {
this.lesson_id = lesson_id;
}
public String getLecturer_id(){return lecturer_id;}
public void setLecturer_id(String lecturer_id){this.lecturer_id=lecturer_id;}
public Lesson getLesson() {
return lesson;
}
public void setLesson(Lesson lesson) {
this.lesson = lesson;
}
public LessonDate getLesson_date() {
return lesson_date;
}
public void setLesson_date(LessonDate lesson_date) {
this.lesson_date = lesson_date;
}
public Venue getVenue() {
return venue;
}
public void setVenue(Venue venue) {
this.venue = venue;
}
public LessonBeacon getLessonBeacon() {
return lessonBeacon;
}
public void setLessonBeacon(LessonBeacon lessonBeacon) {
this.lessonBeacon = lessonBeacon;
}
If i comment the lesson_date &beacon_lesson in the Model, then it can work correctly.And i can get the information. It is very strange.Here is the LessonDate Model.
public class LessonDate {
#SerializedName("id")
#Expose
private String id;
#SerializedName("lesson_id")
#Expose
private String lesson_id;
#SerializedName("ldate")
#Expose
private String ldate;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLesson_id() {
return lesson_id;
}
public void setLesson_id(String lesson_id) {
this.lesson_id = lesson_id;
}
public String getLdate() {
return ldate;
}
public void setLdate(String ldate) {
this.ldate = ldate;
}
public String getDate()
{
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
Date startDate;
String week_day = null;
try
{
startDate = df.parse(ldate);
week_day = getWeekDay(startDate.getDay());
}
catch (Exception e)
{
e.printStackTrace();
}
return week_day;
}
private String getWeekDay(int day)
{
String strWeekDay = null;
switch (day) {
case 1:
strWeekDay = "Monday";
break;
case 2:
strWeekDay = "Tuesday";
break;
case 3:
strWeekDay = "Wednesday";
break;
case 4:
strWeekDay = "Thursday";
break;
case 5:
strWeekDay = "Friday";
break;
case 6:
strWeekDay = "Saturday";
break;
case 7:
strWeekDay = "Sunday";
break;
}
return strWeekDay;
}
}
Here is the BeaconUser Model.
public class BeaconUser {
#SerializedName("id")
#Expose
private String id;
#SerializedName("major")
#Expose
private String major;
#SerializedName("minor")
#Expose
private String minor;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getMinor() {
return minor;
}
public void setMinor(String minor) {
this.minor = minor;
}
}
Thanks for your time reading my question.

Even if i cant find your nested JsonArray since it's one Json-Array wrapped around multiple Json-Object's you can get the Value using
#GET("path/to/your/data")
List<BeaconUser> Users();
If you have nested JsonArrays then you should modify your Model like:
Class MyModel {
List<MyOtherModel> data;
}
while the nested JSONArray is the List within the Model.
In your case it means that LessonDate is another JsonObject (Object->Object) which is not an array and it should work. Please post the Exception to figure out if there is another issue.

Related

How can I set label names manually on a loop springboot?

I have a JSON array below, I want to be able to set label names that make sense instead of the entity names. Am generating tables dynamically using this data, I want the rows to have names that make more sense to the end user by assigning custom Label names. the recordtype generates new tab names
This is my JSON
[
{
"country": "USA",
"projectId": "USAID2020,
"case": "2014",
"recordType": "Identification",
"itemDetails": [
{
"ItemValue": "023",
"Label": "hA",
"ItemValueLabel": "023",
"Name": "hA"
},
{
"ItemValue": "0005",
"Label": "hUM",
"ItemValueLabel": "0005",
"Name": "hUM"
},
{
"ItemValue": "5",
"Label": "hCounty",
"ItemValueLabel": "5",
"Name": "hCounty"
}
]
},
{
"country": "USA",
"projectId": "USAID2020",
"case": "2014",
"recordType": "Eligibility",
"itemDetails": [
{
"ItemValue": "023",
"Label": "hA",
"ItemValueLabel": "023",
"Name": "hA"
},
{
"ItemValue": "0005",
"Label": "hUM",
"ItemValueLabel": "0005",
"Name": "hUM"
},
{
"ItemValue": "0005",
"Label": "hPUM",
"ItemValueLabel": "0005",
"Name": "hPUM"
}
]
}
]
This is how I want the labels to appear
[
{
"country": "USA",
"projectId": "USAID2020,
"case": "2014",
"recordType": "Identification",
"itemDetails": [
{
"ItemValue": "023",
"Label": "Area Code",
"ItemValueLabel": "023",
"Name": "hA"
},
{
"ItemValue": "0005",
"Label": "Manager Identification",
"ItemValueLabel": "0005",
"Name": "hUM"
},
{
"ItemValue": "5",
"Label": "County Name",
"ItemValueLabel": "5",
"Name": "hCounty"
}
]
},
{
"country": "USA",
"projectId": "USAID2020",
"case": "2014",
"recordType": "Eligibility",
"itemDetails": [
{
"ItemValue": "023",
"Label": "Area Code",
"ItemValueLabel": "023",
"Name": "hA"
},
{
"ItemValue": "0005",
"Label": "Manager Identification",
"ItemValueLabel": "0005",
"Name": "hUM"
},
{
"ItemValue": "0005",
"Label": "House Code",
"ItemValueLabel": "0005",
"Name": "hPUM"
}
]
}
]
This is my logic
public ArrayList<Summary> getHouseHoldRecordsByCase(String country, String projectId, String case) {
ArrayList<Summary> documents= new ArrayList<>();
Summary summary = new Summary();
ArrayList<ItemDetails> details = new ArrayList<>();
COVER cover = dataStoreService.getHouseHoldRecordsByCase(country, projectId, caseNumber);
summary.case = caseNumber;
summary.recordType = "Identification";
summary.country = country;
summary.projectId = projectId;
Field[] fields = hsecover.getClass().getDeclaredFields();
for (Field _f:fields){
try {
String val = PropertyUtils.getProperty(hsecover, _f.getName()).toString();
details.add(new ItemDetails(val, _f.getName(), val, _f.getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
summary.itemDetails = details;
documents.add(summary);
summary = new Summary();
ELIGILITY elig = dataStoreService.getEliByCase(country, projectId, case);
summary.recordType = "Eligibility";
summary.case = case;
summary.country = country;
summary.projectId = projectId;
details = new ArrayList<>();
fields = elig.getClass().getDeclaredFields();
for (Field _f:fields){
try {
String val = PropertyUtils.getProperty(elig, _f.getName()).toString();
details.add(new ItemDetails(val, _f.getName(), val, _f.getName()));
} catch (Exception e) {
e.printStackTrace();
}
}
summary.itemDetails = details;
documents.add(summary);
}
return documents;
}
public COVER getHouseHoldRecordsByCase(String country, String projectId, String case) {
COVER usa = cover_repository.findByCase(case);
return usa;
}
public ELIGILITY getEliByCase(String country, String projectId, String case) {
ELIGILITY usa = eligility_repository.findByCaseNumber(case);
return usa;
}
My ItemDetails model class
public class ItemDetails {
public String ItemValue;
public String Label;
public String ItemValueLabel;
public String Name;
public ItemDetails(String itemValue, String label, String itemValueLabel, String name) {
ItemValue = itemValue;
Label = label;
ItemValueLabel = itemValueLabel;
Name = name;
}
}
My Summary class
public class Summary {
public String country;
public String projectId;
public String case;
public String recordType;
public ArrayList<ItemDetails> itemDetails;
}
The data comes from a database.
How can I set the label names with names that make sense instead of coming as entity names?
You Can use #JsonProperty("different names") on each fields
Or you can use #JsonSetter("different name") on setter method level.

Elasticsearch Rest High Level Client aggregate fields dynamically

I am trying to generate query dynamically based on the inputs but in the generated query i can see there are only two aggregations are getting generated how can i make each fields to have the separate aggregations below is the code what i have tried and the response what i'm getting.
From main() i'm calling
buildSearchCriteria("1");
Here i am setting the aggregation type and respective values:
public static void buildSearchCriteria(String... exceptionId) {
SearchCriteria searchCriteria = new SearchCriteria();
Map<String, List<FieldNameAndPath>> stringListMap = new HashMap<>();
stringListMap.put("nested", asList(new FieldNameAndPath("nested", "recommendations",
"recommendations", null, emptyList(), 1)));
stringListMap.put("filter", asList(new FieldNameAndPath("filter", "exceptionIds", "recommendations.exceptionId.keyword",
asList(exceptionId),
asList(new NestedAggsFields("terms", "exceptionIdsMatch")), 2)));
stringListMap.put("terms", asList(new FieldNameAndPath("terms", "by_exceptionId", "recommendations.exceptionId.keyword", null, emptyList(), 3),
new FieldNameAndPath("terms", "by_item", "recommendations.item.keyword", null, emptyList(), 4),
new FieldNameAndPath("terms", "by_destination", "recommendations.location.keyword", null, emptyList(), 5),
new FieldNameAndPath("terms", "by_trans", "recommendations.transportMode.keyword", null, emptyList(), 6),
new FieldNameAndPath("terms", "by_sourcelocation", "recommendations.sourceLocation.keyword", null, emptyList(), 7),
new FieldNameAndPath("terms", "by_shipdate", "recommendations.shipDate", null, emptyList(), 8),
new FieldNameAndPath("terms", "by_arrival", "recommendations.arrivalDate", null, emptyList(), 9)));
stringListMap.put("sum", asList(new FieldNameAndPath("sum", "quantity", "recommendations.transferQuantity", null, emptyList(), 10),
new FieldNameAndPath("sum", "transfercost", "recommendations.transferCost", null, emptyList(), 11),
new FieldNameAndPath("sum", "revenueRecovered", "recommendations.revenueRecovered", null, emptyList(), 12)));
System.out.println(stringListMap);
searchCriteria.setStringListMap(stringListMap);
aggregate(searchCriteria);
}
Below is the aggregate function which will get the the above information and builds query:
public static void aggregate(SearchCriteria searchCriteria) throws IOException {
Map<String, List<FieldNameAndPath>> map = searchCriteria.getStringListMap();
List<FieldNameAndPath> nesteds = map.get("nested");
List<FieldNameAndPath> filter = map.get("filter");
List<FieldNameAndPath> terms = map.get("terms");
List<FieldNameAndPath> sums = map.get("sum");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
AggregationBuilder aggregationBuilder = new SamplerAggregationBuilder("parent");
nesteds.stream().forEach(l -> buildAggregations(l, aggregationBuilder));
filter.stream().forEach(l -> buildAggregations(l, aggregationBuilder));
terms.stream().forEach(l -> buildAggregations(l, aggregationBuilder));
sums.stream().forEach(l -> buildAggregations(l, aggregationBuilder));
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("index");
searchRequest.types("type");
sourceBuilder.aggregation(aggregationBuilder);
searchRequest.source(sourceBuilder);
System.out.println(searchRequest.source().toString());
}
buildAggregations method:
private static AggregationBuilder buildAggregations(FieldNameAndPath fieldNameAndPath , AggregationBuilder parentAggregationBuilder) {
if(fieldNameAndPath.getAggType().equals("nested")){
parentAggregationBuilder = AggregationBuilders.nested(fieldNameAndPath.getFieldName(), fieldNameAndPath.getFieldPath());
}
if(fieldNameAndPath.getAggType().equals("filter")){
parentAggregationBuilder.subAggregation(AggregationBuilders
.filter(fieldNameAndPath.getFieldName(),
QueryBuilders.termsQuery(fieldNameAndPath.getNestedAggs()
.stream().map(nestedAggsFields -> nestedAggsFields.getFieldName()).findFirst().get(), fieldNameAndPath.getFieldValues())));
}
if(fieldNameAndPath.getAggType().equals("terms")){
parentAggregationBuilder.subAggregation(AggregationBuilders.terms(fieldNameAndPath.getFieldName())
.field(fieldNameAndPath.getFieldPath()));
}
if(fieldNameAndPath.getAggType().equals("sum")){
parentAggregationBuilder.subAggregation(AggregationBuilders.
sum(fieldNameAndPath.getFieldName()).field(fieldNameAndPath.getFieldPath()));
}
return parentAggregationBuilder;
}
SearchCriteria class:
#Data
public class SearchCriteria {
Map<String, List<FieldNameAndPath>> stringListMap;
private List<String> searchFields;
}
And the DTO FieldNameAndPath:
public class FieldNameAndPath{
private String aggType;
private String fieldName;
private String fieldPath;
private List<String> fieldValues;
private List<NestedAggsFields> nestedAggs;
private int order;
}
And the query output from the above code is:
{
"aggregations": {
"parent": {
"sampler": {
"shard_size": 100
},
"aggregations": {
"exceptionIds": {
"filter": {
"terms": {
"exceptionIdsMatch": [
"1"
],
"boost": 1
}
}
},
"by_exceptionId": {
"terms": {
"field": "recommendations.exceptionId.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_item": {
"terms": {
"field": "recommendations.item.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_destination": {
"terms": {
"field": "recommendations.location.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_trans": {
"terms": {
"field": "recommendations.transportMode.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_sourcelocation": {
"terms": {
"field": "recommendations.sourceLocation.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_shipdate": {
"terms": {
"field": "recommendations.shipDate",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"by_arrival": {
"terms": {
"field": "recommendations.arrivalDate",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"quantity": {
"sum": {
"field": "recommendations.transferQuantity"
}
},
"transfercost": {
"sum": {
"field": "recommendations.transferCost"
}
},
"revenueRecovered": {
"sum": {
"field": "recommendations.revenueRecovered"
}
}
}
}
}
}
Expected Query is:
{
"size": 0,
"aggregations": {
"exceptionIds": {
"nested": {
"path": "recommendations"
},
"aggregations": {
"exceptionIdsMatch": {
"filter": {
"terms": {
"recommendations.exceptionId.keyword": [
"1"
],
"boost": 1
}
},
"aggregations": {
"by_exceptionId": {
"terms": {
"field": "recommendations.exceptionId.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_item": {
"terms": {
"field": "recommendations.item.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_destination": {
"terms": {
"field": "recommendations.location.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_trans": {
"terms": {
"field": "recommendations.transportMode.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_sourcelocation": {
"terms": {
"field": "recommendations.sourceLocation.keyword",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_shipdate": {
"terms": {
"field": "recommendations.shipDate",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"by_arrival": {
"terms": {
"field": "recommendations.arrivalDate",
"size": 10,
"min_doc_count": 1,
"shard_min_doc_count": 0,
"show_term_doc_count_error": false,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
},
"aggregations": {
"quantity": {
"sum": {
"field": "recommendations.transferQuantity"
}
},
"transfercost": {
"sum": {
"field": "recommendations.transferCost"
}
},
"revenueRecovered": {
"sum": {
"field": "recommendations.revenueRecovered"
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}

how to parse the json response which starts with an array

response:
[
{
"id": "e9299032e8a34d168def176af7d62da3",
"createdAt": "Nov 8, 2017 9:46:40 AM",
"model": {
"id": "eeed0b6733a644cea07cf4c60f87ebb7",
"name": "color",
"app_id": "main",
"created_at": "May 11, 2016 11:35:45 PM",
"model_version": {}
},
"input": {
"id": "df6eae07cd86483f811c5a2202e782eb",
"data": {
"concepts": [],
"metadata": {},
"image": {
"url": "http://www.sachinmittal.com/wp-content/uploads/2017/04/47559184-image.jpg"
}
}
},
"data": [
{
"hex": "#f59b2d",
"webSafeHex": "#ffa500",
"webSafeColorName": "Orange",
"value": 0.0605
},
{
"hex": "#3f1303",
"webSafeHex": "#000000",
"webSafeColorName": "Black",
"value": 0.2085
},
{
"hex": "#a33303",
"webSafeHex": "#8b0000",
"webSafeColorName": "DarkRed",
"value": 0.3815
},
{
"hex": "#000000",
"webSafeHex": "#000000",
"webSafeColorName": "Black",
"value": 0.34275
},
{
"hex": "#f7ce93",
"webSafeHex": "#ffdead",
"webSafeColorName": "NavajoWhite",
"value": 0.00675
}
],
"status": {}
}
]
need to parse this reponse in json. Please help me out.
You can try something like this..
try{
JSONArray array= new JSONArray(Yourresponse);
for(int i=0; i<=array.length();i++){
JSONObject jsonObject=array.getJSONObject(i);
String id= jsonObject.getString("id");
String created_at= jsonObject.getString("createdAt");
String model_id = jsonObject.getJSONObject("model").getString("id");
String app_id=jsonObject.getJSONObject("model").getString("app_id");
//So On... Depends on your requirements. It's just an idea!
}
}
catch (Exception e){
e.printStackTrace();
}

How to Make POJO class when response have mix data. some key contain Object and some have array type data

I am using retrofit2 to Make network request,I have searched over here but my bad luck i couldn't find any working solution. that's why i am putting my question here.
my JSON response is given below.
The problem is sometimes the REST API returns an Array of hour , but sometimes it is just a Object. How does one handle such a situation?
Is there an elegant way to handle a mixed array like this in Retrofit/Gson? I'm not responsible for the data coming from the API, so I don't think changing that will be an option.Any help would be appreciated.
{
"status": "success",
"data": [
{
"id": 30,
"name": "Rh.poutiqe",
"global_delay": "0",
"approved": true,
"min_order": "0.000",
"has_pickup": 0,
"address": {
"id": "35",
"name": "Store Address",
"type": "house",
"block_number": "8",
"street": "85",
"avenue": "0",
"building": "2",
"floor": "",
"apartment": "",
"directions": "",
"lat": null,
"lng": null,
"city": {
"id": "79",
"name": "Bayan",
"zone": "3",
"governate": "Hawally"
}
},
"status": "Available",
"owner": {
"id": "32",
"username": "+96550199900",
"creation_date": "2017-08-07 09:46:49",
"info": {
"name": "Asmaa alkandri",
"email": "Asooma_q8#hotmail.com",
"mobile": "50199900",
"store_id": "30",
"device_token": "e01efb2f03cd43509242c7b38ca890471db2e5b056f50b7a3661c34ab45b0b6e"
},
"addresses": [
{
"id": "35",
"name": "Store Address",
"type": "house",
"block_number": "8",
"street": "85",
"avenue": "0",
"building": "2",
"floor": "",
"apartment": "",
"directions": "",
"lat": null,
"lng": null,
"city": {
"id": "79",
"name": "Bayan",
"zone": "3",
"governate": "Hawally"
}
}
]
},
"open": false,
"image": {
"src": "https://api.bits.com.kw/assets/stores/30/y1nzl.jpg"
},
"hours": {
"2": [
{
"id": "117",
"day_id": "2",
"day_of_week": "Tuesday",
"start_hour": "1400",
"end_hour": "2300"
}
],
"3": [
{
"id": "118",
"day_id": "3",
"day_of_week": "Wednesday",
"start_hour": "1400",
"end_hour": "2300"
}
]
},
"next_available": {
"day_of_week": "Tuesday",
"start_hour": "1400",
"end_hour": "2300",
"day_id": "2",
"date": "2017-09-19"
}
},
{
"id": 57,
"name": "RH Kitchen",
"global_delay": "0",
"approved": true,
"min_order": "0.000",
"has_pickup": 0,
"address": {
"id": "63",
"name": "Store Address",
"type": "house",
"block_number": "5",
"street": "2",
"avenue": "",
"building": "97",
"floor": "",
"apartment": "",
"directions": "",
"lat": null,
"lng": null,
"city": {
"id": "79",
"name": "Bayan",
"zone": "3",
"governate": "Hawally"
}
},
"status": "Not Receiving Orders",
"owner": {
"id": "57",
"username": "+96566659454",
"creation_date": "2017-09-09 11:32:19",
"info": {
"name": "RH Kitchen",
"email": "taiba.aldarmi#gmail.com",
"mobile": "66659454",
"store_id": "57",
"device_token": "f6fffd3a393e9aea53863cffbb55b51a3afd2475e952091ea362a85fc930ec9a"
},
"addresses": [
{
"id": "63",
"name": "Store Address",
"type": "house",
"block_number": "5",
"street": "2",
"avenue": "",
"building": "97",
"floor": "",
"apartment": "",
"directions": "",
"lat": null,
"lng": null,
"city": {
"id": "79",
"name": "Bayan",
"zone": "3",
"governate": "Hawally"
}
}
]
},
"open": false,
"image": {
"src": "https://api.bits.com.kw/placeholder.jpg"
},
"hours": [],
"next_available": false
},
{
"id": 64,
"name": "Lets__shop",
"global_delay": "1440",
"approved": true,
"min_order": "5.000",
"has_pickup": 0,
"address": {
"id": "64",
"name": "Store Address",
"type": "house",
"block_number": "3",
"street": "312",
"avenue": "",
"building": "56",
"floor": "",
"apartment": "",
"directions": "",
"lat": "0.000000000000000000",
"lng": "0.000000000000000000",
"city": {
"id": "126",
"name": "Saad Al Abdullah",
"zone": "9",
"governate": "Jahra"
}
},
"status": "Available",
"owner": {
"id": "58",
"username": "+96555899184",
"creation_date": "2017-09-09 18:33:12",
"info": {
"name": "Moneera ibrahim",
"email": "Moneeera96#gmail.com",
"mobile": "55899184",
"store_id": "64",
"device_token": null
},
"addresses": [
{
"id": "64",
"name": "Store Address",
"type": "house",
"block_number": "3",
"street": "312",
"avenue": "",
"building": "56",
"floor": "",
"apartment": "",
"directions": "",
"lat": "0.000000000000000000",
"lng": "0.000000000000000000",
"city": {
"id": "126",
"name": "Saad Al Abdullah",
"zone": "9",
"governate": "Jahra"
}
}
]
},
"open": true,
"next_available": {
"day_of_week": "Today",
"start_hour": "1646",
"end_hour": "2230",
"day_id": "0",
"date": "2017-09-17 1646"
},
"image": {
"src": "https://api.bits.com.kw/assets/stores/64/0xqh4.jpg"
},
"hours": [
[
{
"id": "161",
"day_id": "0",
"day_of_week": "Sunday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "162",
"day_id": "1",
"day_of_week": "Monday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "163",
"day_id": "2",
"day_of_week": "Tuesday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "164",
"day_id": "3",
"day_of_week": "Wednesday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "165",
"day_id": "4",
"day_of_week": "Thursday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "166",
"day_id": "5",
"day_of_week": "Friday",
"start_hour": "730",
"end_hour": "2230"
}
],
[
{
"id": "167",
"day_id": "6",
"day_of_week": "Saturday",
"start_hour": "730",
"end_hour": "2230"
}
]
]
}
]
}
I have Make POJO class like:
public class StoreModel implements Parcelable{
#SerializedName("id")
public int id;
#SerializedName("name")
public String name;
#SerializedName("global_delay")
public String global_delay;
#SerializedName("approved")
public boolean approved;
#SerializedName("min_order")
public String min_order;
#SerializedName("has_pickup")
public int has_pickup;
#SerializedName("address")
public AddressModel address;
#SerializedName("status")
public String status;
#SerializedName("owner")
public OwnerModel owner;
#SerializedName("open")
public boolean open;
#SerializedName("next_available")
public Object next_available;
#SerializedName("image")
public ImageModel image;
protected StoreModel(Parcel in) {
id = in.readInt();
name = in.readString();
global_delay = in.readString();
approved = in.readByte() != 0;
min_order = in.readString();
has_pickup = in.readInt();
address = in.readParcelable(AddressModel.class.getClassLoader());
status = in.readString();
owner = in.readParcelable(OwnerModel.class.getClassLoader());
open = in.readByte() != 0;
image = in.readParcelable(ImageModel.class.getClassLoader());
//next_available = in.readParcelable(NextAvailableModel.class.getClassLoader());
}
public static final Creator<StoreModel> CREATOR = new Creator<StoreModel>() {
#Override
public StoreModel createFromParcel(Parcel in) {
return new StoreModel(in);
}
#Override
public StoreModel[] newArray(int size) {
return new StoreModel[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel parcel, int i) {
parcel.writeInt(id);
parcel.writeString(name);
parcel.writeString(global_delay);
parcel.writeByte((byte) (approved ? 1 : 0));
parcel.writeString(min_order);
parcel.writeInt(has_pickup);
parcel.writeParcelable(address, i);
parcel.writeString(status);
parcel.writeParcelable(owner, i);
parcel.writeByte((byte) (open ? 1 : 0));
parcel.writeParcelable(image, i);
/*if(next_available instanceof NextAvailableModel)
parcel.writeParcelable((NextAvailableModel)next_available, i);
else if(next_available instanceof Boolean)
parcel.writeByte((byte) ((Boolean)next_available ? 1 : 0));*/
}
#SerializedName("hours")
#Expose
public List<List<HoursModel>> hours;
}
**And HoursModel Java Class**
public class HoursModel implements Parcelable{
#SerializedName("id")
public String id;
#SerializedName("day_id")
public String day_id;
#SerializedName("day_of_week")
public String day_of_week;
#SerializedName("start_hour")
public String start_hour;
#SerializedName("end_hour")
public String end_hour;
protected HoursModel(Parcel in) {
id = in.readString();
day_id = in.readString();
day_of_week = in.readString();
start_hour = in.readString();
end_hour = in.readString();
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(id);
dest.writeString(day_id);
dest.writeString(day_of_week);
dest.writeString(start_hour);
dest.writeString(end_hour);
}
#Override
public int describeContents() {
return 0;
}
public static final Creator<HoursModel> CREATOR = new Creator<HoursModel>() {
#Override
public HoursModel createFromParcel(Parcel in) {
return new HoursModel(in);
}
#Override
public HoursModel[] newArray(int size) {
return new HoursModel[size];
}
};
}
First, if possible, verify if you can fix this braindead API. :)
First of all, notice that the API returns 2 very different types of data:
list of hours (no keys)
map of hours (each element has a key!)
You'll need to represent this structure in your POJO somehow. Maybe a list of key-hour pairs, like List<Pair<String, Hour>, with nullable key? Your call.
Second, you need to create a custom TypeAdapter that can deserialize a list and/or map into a Java object.
Once you have a type adapter, you can either attach it to a field using #JsonAdapter annotation, or register custom type in Gson builder.
https://google.github.io/gson/apidocs/com/google/gson/annotations/JsonAdapter.html
http://www.javacreed.com/gson-typeadapter-example/

Custom deserializer or different class design Retrofit

Retrofit makes things so easy for a noob like me. However, the API response structure that I'm requesting for my current project doesn't follow the same format as I have used before. I am unsure of whether I need to rewrite my POJO or make a custom deserializer in GSON. I cannot change the JSON structure and a custom deserializer seems daunting to me.
Here is the JSON:
{
"Green Shirt": [
{
"id": "740",
"name": “Nice Green Shirt",
"quantity": "0",
"make": "",
"model": "",
"price": “15.00",
"size": "XXS",
"sku": null,
"image": "https:\/\/google.com\/green_shirt.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
},
{
"id": "743",
"name": "Green Shirt",
"quantity": “68",
"make": "",
"model": "",
"price": “20.00",
"size": "XS",
"sku": null,
"image": "https:\/\/google.com\/green_shirt.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
}
],
"Dark Blue Jeans": [
{
"id": "1588",
"name": "Dark Blue Jeans",
"quantity": "0",
"make": "",
"model": "",
"price": "0.00",
"size": “S",
"sku": null,
"image": "https:\/\/google.com\/dark_blue_jeans.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
},
{
"id": "1559",
"name": "Dark Blue Jeans",
"quantity": "4",
"make": "",
"model": "",
"price": "0.00",
"size": “XL",
"sku": null,
"image": "https:\/\/google.com\/dark_blue_jeans.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
}
],
"White Belt": [
{
"id": "1536",
"name": "White Belt",
"quantity": "37",
"make": "",
"model": "",
"price": "0.00",
"size": "One Size",
"sku": null,
"image": "https:\/\/google.com\/white_belt.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
}
]
}
Here is the POJO:
public class Product
{
private String model;
private String bar_code;
private String image;
private null sku;
private String new_record;
private String size;
private String id;
private null category;
private String price;
private String category_name;
private String name;
private String quantity;
private String make;
public String getModel ()
{
return model;
}
public void setModel (String model)
{
this.model = model;
}
public String getBar_code ()
{
return bar_code;
}
public void setBar_code (String bar_code)
{
this.bar_code = bar_code;
}
public String getImage ()
{
return image;
}
public void setImage (String image)
{
this.image = image;
}
public null getSku ()
{
return sku;
}
public void setSku (null sku)
{
this.sku = sku;
}
public String getNew_record ()
{
return new_record;
}
public void setNew_record (String new_record)
{
this.new_record = new_record;
}
public String getSize ()
{
return size;
}
public void setSize (String size)
{
this.size = size;
}
public String getId ()
{
return id;
}
public void setId (String id)
{
this.id = id;
}
public null getCategory ()
{
return category;
}
public void setCategory (null category)
{
this.category = category;
}
public String getPrice ()
{
return price;
}
public void setPrice (String price)
{
this.price = price;
}
public String getCategory_name ()
{
return category_name;
}
public void setCategory_name (String category_name)
{
this.category_name = category_name;
}
public String getName ()
{
return name;
}
public void setName (String name)
{
this.name = name;
}
public String getQuantity ()
{
return quantity;
}
public void setQuantity (String quantity)
{
this.quantity = quantity;
}
public String getMake ()
{
return make;
}
public void setMake (String make)
{
this.make = make;
}
#Override
public String toString()
{
return "ClassPojo [model = "+model+", bar_code = "+bar_code+", image = "+image+", sku = "+sku+", new_record = "+new_record+", size = "+size+", id = "+id+", category = "+category+", price = "+price+", category_name = "+category_name+", name = "+name+", quantity = "+quantity+", make = "+make+"]";
}
}
Here is the request and Retrofit interface:
public static void requestData(String username,String password) {
RestAdapter.Builder builder = new RestAdapter.Builder()
.setClient(new OkClient(new OkHttpClient()))
.setEndpoint(ENDPOINT);
if (username != null && password != null) {
// concatenate username and password with colon for authentication
final String credentials = username + ":" + password;
builder.setRequestInterceptor(new RequestInterceptor() {
#Override
public void intercept(RequestFacade request) {
// create Base64 encodet string
String string = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
request.addHeader("Accept", "application/json");
request.addHeader("Authorization", string);
}
});
}
RestAdapter adapter = builder.build();
ProductAPI api = adapter.create(ProductAPI.class);
api.getInventory(new Callback<List<Product>>() {
#Override
public void success(List<Product> products, Response response) {
Log.d(TAG, response.getUrl());
Log.d(TAG, response.getReason());
mInventory = product;
}
#Override
public void failure(RetrofitError error) {
Log.d(TAG,error.getMessage());
}
});
}
public interface ProductAPI {
#GET("/v2/get-inventory")
public void getInventory(Callback<List<Product>> response);
}
This is the error I get because the JSON starts with '{' instead of '['
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
Your JSON is invalid, try formatting it properly first before doing anything else.
Properly formatted:
{
"Green Shirt": [
{
"id": "740",
"name": "Nice Green Shirt",
"quantity": "0",
"make": "",
"model": "",
"price": "15.00",
"size": "XXS",
"sku": null,
"image": "https:\\/\\/google.com\\/green_shirt.jpg",
"new_record": false,
"category_name": "",
"bar_code": ""
},
{
"id": "743",
"name": "Green Shirt",
"quantity": "68",
"make": "",
"model": "",
"price": "20.00",
"size": "XS",
"sku": null,
"image": "https:\\/\\/google.com\\/green_shirt.jpg",
"new_record": false,
"category_name": "",
"bar_code": ""
}
],
"Dark Blue Jeans": [
{
"id": "1588",
"name": "Dark Blue Jeans",
"quantity": "0",
"make": "",
"model": "",
"price": "0.00",
"size": "S",
"sku": null,
"image": "https:\\/\\/google.com\\/dark_blue_jeans.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
},
{
"id": "1559",
"name": "Dark Blue Jeans",
"quantity": "4",
"make": "",
"model": "",
"price": "0.00",
"size": "XL",
"sku": null,
"image": "https:\\/\\/google.com\\/dark_blue_jeans.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
}
],
"White Belt": [
{
"id": "1536",
"name": "White Belt",
"quantity": "37",
"make": "",
"model": "",
"price": "0.00",
"size": "One Size",
"sku": null,
"image": "https:\\/\\/google.com\\/white_belt.jpg",
"new_record": false,
"category_name": "",
"bar_code": "",
"category": null
}
]
}
Some of the errors it had:
Error:Strings should be wrapped in double quotes.[Code 17, Structure 12]
Error:Strings should be wrapped in double quotes.[Code 17, Structure 28]
Error:Invalid comma, expecting }.[Code 141, Structure 53]
Error:Expecting string, not }.[Code 8, Structure 54]
Error:Strings should be wrapped in double quotes.[Code 17, Structure 67]
Error:Strings should be wrapped in double quotes.[Code 17, Structure 79]
Error:Invalid comma, expecting }.[Code 141, Structure 104]
Error:Expecting string, not }.[Code 8, Structure 105]
Error:Strings should be wrapped in double quotes.[Code 17, Structure 138]
Error:Strings should be wrapped in double quotes.[Code 17, Structure 192]
The problem seems exactly what it says. The response is an object that has an array and not an array directly:
{ [{},{},{}] }
If the response was:
[{},{},{}]
It would work, but as you cannot change the response format you should change your java. Instead of expecting a List of Products you should have an object that has a List of Products inside. That is how retrofit will map it.
Edit:
The response is actually as follows:
{[],[],[]}
Is not a list, is an object composed with three Lists of Objects Product
The mapping to an object will have to be:
public class Wrapper
{
List<Product> WhiteBelt;
List<Product> DarkBlueJeans;
List<Product> GreenShirt;
}
Something like that would be your structure. I dont believe is right, because you usally want a list and not an object with three lists inside "hardcoded".
Let me know if it helps
Edited:
So you need somthing like this:
{
"products":
[{ "name" : "Green Shirt"
"items":
[{"id": "740",
"name": “Nice Green Shirt",
"quantity": "0",
"make": "",
"model": "",
"price": “15.00",
"size": "XXS",
"sku": null,
"image": "https:\/\/google.com\/green_shirt.jpg",
"new_record": false,
"category_name": "",
"bar_code": ""
}]
}]
}
That would be a structure that accepts a list of Products and inside each prodcut you have the list of items (the one you already have).
In Java:
public class ProductList
{
List <ProductList> productList;
}
public class ProductList
{
String name;
List<Product> items;
}
Using your original Product class
I told Retrofit (GSON?) to look for a Map<String,List<Product>> instead of just a List<Product> and it figured it out, how convenient.
:
api.getInventory(new Callback<Map<String,List<Product>>>() {
#Override
public void success(Map<String,List<Product>> products, Response response) {
mInventory = products;
}
#Override
public void failure(RetrofitError error) {
Log.d(TAG,error.getMessage());
}
});
public interface ProductAPI {
#GET("/v2/get-inventory")
public void getInventory(Callback<Map<String,List<Product>>> response);
}

Categories

Resources