I have such service:
public interface FireService {
void addTags(String sessionId, List<TagCreateRequest> tags);
}
Here TagCreateRequest is:
#MetaClass(name = "...")
public class TagCreateRequest extends AbstractNotPersistentEntity implements Serializable {
#MetaProperty(mandatory = true)
protected TagType type;
#MetaProperty(mandatory = true)
protected Double time;
#MetaProperty
protected String text;
public void setType(TagType type) {
this.type = type;
}
public TagType getType() {
return type;
}
public void setTime(Double time) {
this.time = time;
}
public Double getTime() {
return time;
}
public void setText(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
My problem is when i'm trying to make REST request to method addTags like this:
http://localhost:8080/app/rest/v2/services/fire_FireService/addTags
{
"sessionId": "1417270d-31cb-be3c-e583-4b172b4183a9",
"tags": [
{
"type": "fire",
"time": 12.333
},
{
"type": "text",
"time": 15.12,
"text": "Test!!!"
}
]
}
I'm getting the EntitySerializationException that tells me that MetaClass for entity is not defined:
EntitySerializationException: Cannot deserialize an entity. MetaClass is not defined
I tried to look how platform determines the MetaClass and found strange thing. If service parameter is Collection, then passed MetaClass is null:
#Component("cuba_RestParseUtils")
public class RestParseUtils {
...
public Object toObject(Class clazz, String value) throws ParseException {
...
if (Collection.class.isAssignableFrom(clazz)) {
return entitySerializationAPI.<Entity>entitiesCollectionFromJson(value, null);
}
...
}
...
}
What should i do in this case?
You must explicitly specify the type of instances in the collection. Use the _entityName field in each TagCreateRequest entity:
{
"sessionId": "1417270d-31cb-be3c-e583-4b172b4183a9",
"tags": [
{
"_entityName": "prj_TagMetaClassName",
"type": "fire",
"time": 12.333
},
{
"_entityName": "prj_TagMetaClassName",
"type": "text",
"time": 15.12,
"text": "Test!!!"
}
]
}
Related
Here is the sample JSON string. I want to parse this nested JSON object even though nested object have the same name. Some time we may have multiple levels of the nested objects. I tired with Jackson nested objects parsing but that did not work for me. After parsing the object, i want to convert that into a different format.Please help me in parsing this JSON. Thanks in advance.
{
"operator": "and",
"predicates": [
{
"operator": "and",
"predicates": [
{
"columnName": "userName",
"datatype": "string",
"input": "text",
"operand": "equal",
"value": "xxxx"
},
{
"columnName": "Age",
"datatype": "number",
"input": "number",
"operand": "greater_or_equal",
"value": "21"
}
]
},
{
"operator": "and",
"predicates": [
{
"columnName": "userName",
"datatype": "string",
"input": "text",
"operand": "not_equal",
"value": "nnn"
},
{
"columnName": "Birthday",
"datatype": "date",
"input": "date_picker",
"operand": "in",
"value": "2020-07-23,2020-07-24"
}
]
}
]
}
below is the code in java
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonProperty;
public class Predicates {
private String columnName;
private String datatype;
private String input;
private String operator;
private String value;
private String operand;
/**
*
*/
private List<Predicates> predicates;
#JsonProperty("predicates")
private void unpackNested(Map<String,Object> predicates) {
this.columnName = (String)predicates.get("columnName");
this.datatype = (String)predicates.get("datatype");
this.input = (String)predicates.get("input");
this.operator = (String)predicates.get("operator");
this.value = (String)predicates.get("value");
this.operand = (String)predicates.get("operand");
}
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDatatype() {
return datatype;
}
public void setDatatype(String datatype) {
this.datatype = datatype;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public String getOperator() {
return operator;
}
public void setOperator(String operator) {
this.operator = operator;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getOperand() {
return operand;
}
public void setOperand(String operand) {
this.operand = operand;
}
public List<Predicates> getPredicates() {
return predicates;
}
public void setPredicates(List<Predicates> predicates) {
this.predicates = predicates;
}
}
Parsing
ObjectMapper mapper = new ObjectMapper();
Predicates pr = mapper.readValue(json, Predicates.class);
I don't know what you are trying to achieve with your unpackNested method. Jackson can already bind properties from your JSON to your objects and handles recursive properties just fine.
I simply removed your unpackNested method and ran your code on your provided input:
ObjectMapper mapper = new ObjectMapper();
Predicates pr = mapper.readValue(json, Predicates.class);
The object pr contains the full json including the nested child predicates. (I ran the code with jackson databind 2.11.2).
If your properties are not auto-detected, annotate your getters with #JsonProperty:
class Predicate {
// ..snip..
#JsonProperty("input")
public String getInput() {
return input;
}
#JsonProperty("predicates")
public List<Predicates> getPredicates() {
return predicates;
}
}
But apart from that, no extra steps need to be taken. Jackson can already unpack nested objects, just remove your (weird) unpackNested method and let Jackson do its job.
I have a sample object which is referenced by swagger to create a POST endpoint in my documentation.
I then use the documentation to generate a client for testing. However, the API works slightly differently then how the object is directly presented. I want to override the POST body parameter type of the created model in the documentation from a service type to a string (a reference string to the service). I've included the referenced object below.
#Entity
public class ServiceType {
private String id;
private Service service;
private String type;
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
The body is generate as:
{
"createdDate": "2019-03-12T15:18:22.568Z",
"id": "string",
"service": {
"createdDate": "2019-03-12T15:18:22.568Z",
"id": "string",
"name": "string",
"routingKey": "string",
"updatedBy": "string",
"updatedDate": "2019-03-12T15:18:22.569Z"
},
"type": "string",
"updatedBy": "string",
"updatedDate": "2019-03-12T15:18:22.569Z"
}
But I want it to be in the format:
{
"createdDate": "2019-03-12T15:18:22.568Z",
"id": "string",
"service": "string",
"type": "string",
"updatedBy": "string",
"updatedDate": "2019-03-12T15:18:22.569Z"
}
Not sure if this is possible. Thanks for the help.
You can use the #ApiModel and #ApiModelProperty annotations to override the default data type for a field. Note that the data type must be a fully-qualified type name (such as java.lang.String). For more information, see Overriding Property Datatypes.
#Entity
#ApiModel
public class ServiceType {
private String id;
#ApiModelProperty(dataType = "java.lang.String")
private Service service;
private String type;
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
I have below response for one of my web service and I'm using Retrofit and GSON.
{
"error": false,
"Timeline": {
"Date": "2040-06-15",
"bandList": {
"breakfast": {
"dosageList": {
"01": {
"packed": "true",
"medicineList": [
{
"medicine": {
"id": "01",
"name": "glipizide 5 mg tablet, 100 ",
"category": "regular",
"image": null,
"indication": "NIDDM",
"packed": true,
"med_id": "352",
"dosage": 1
}
},
{
"medicine": {
"id": "04",
"name": "Frusemide (Terry White Chemists) 20 mg uncoated tablet, 100 ",
"category": "regular",
"image": null,
"indication": "Fluid",
"packed": true,
"med_id": "4",
"dosage": 2
}
}
]
},
"02": {
"packed": "false",
"medicineList": [
{
"medicine": {
"id": "05",
"name": "Refresh Tears Plus 0.5% eye drops solution, 15 mL ",
"category": "regular",
"image": null,
"indication": "Dry Eyes",
"packed": false,
"med_id": "372",
"dosage": 1
}
}
]
}
}
}
}
}
}
Q1.
Is there a way to parse above response using model classes (POJOs) or without them? I'm stuck at generating model classes for above structure. How do I generate POJOs for above JSON?
Q2. I'm in a position how to convince to send below response, what is the correct structure/format for JSON? Is there any JSON standard I could show to the web developer to get this JSON format? (note:I'm okay to parse this structure)
{
"error": false,
"Timeline": {
"Date": "2040-06-15",
"band": [
{
"name": "breakfast",
"dosage": [
{
"id": "01",
"packed": "true",
"medicine": [
{
"id": "01",
"name": "glipizide 5 mg tablet, 100 ",
"category": "regular",
"image": null,
"indication": "NIDDM",
"packed": true,
"med_id": "52",
"dosage": 1
},
{
"id": "04",
"name": "Frusemide (Terry White Chemists) 20 mg uncoated tablet, 100 ",
"category": "regular",
"image": null,
"indication": "Fluid",
"packed": true,
"med_id": "54",
"dosage": 2
}
]
},
{
"id": "02",
"packed": "false",
"medicine": [
{
"id": "05",
"name": "Refresh Tears Plus 0.5% eye drops solution, 15 mL ",
"category": "regular",
"image": null,
"indication": "Dry Eyes",
"packed": false,
"med_id": "372",
"dosage": 1
}
]
}
]
}
]
}
}
Thank you in advance.
EDIT
I use to autogenerate POJOs using those sites, but its giving below responses for some classes. How do I convert this to proper class?
package ;
public class DosageList
{
private 01 01;
private 02 02;
public void set01(01 01){
this.01 = 01;
}
public 01 get01(){
return this.01;
}
public void set02(02 02){
this.02 = 02;
}
public 02 get02(){
return this.02;
}
}
EDIT 2
I have almost done parsing first JSON, but stuck in here.
for (String bandName: event.getTimeline().getBand().keySet()) {
Log.d("<<<--Band-->>>", "Value " + event.getTimeline().getBand().get(bandName));
Band band = event.getTimeline().getBand().get(bandName);
for (String dosageName:band.getDosage().keySet()) {
Dosage dosage = band.getDosage().get(dosageName);
Log.d("<<<--Dosage-->>>", "Value " + dosage.getMedicine());
for (Medicine medicine: dosage.getMedicine()) {
Log.d("<<<--Medicine-->>>", "Value " + dosage.getMedicine().get(0));
}
}
}
How do I retrieve medicine values?
public class Medicine
{
private String id;
private String name;
private String category;
private String image;
private String indication;
private boolean packed;
private String med_id;
private int dosage;
public void setId(String id){
this.id = id;
}
public String getId(){
return this.id;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setCategory(String category){
this.category = category;
}
public String getCategory(){
return this.category;
}
public void setImage(String image){
this.image = image;
}
public String getImage(){
return this.image;
}
public void setIndication(String indication){
this.indication = indication;
}
public String getIndication(){
return this.indication;
}
public void setPacked(boolean packed){
this.packed = packed;
}
public boolean getPacked(){
return this.packed;
}
public void setMed_id(String med_id){
this.med_id = med_id;
}
public String getMed_id(){
return this.med_id;
}
public void setDosage(int dosage){
this.dosage = dosage;
}
public int getDosage(){
return this.dosage;
}
}
import java.util.ArrayList;
import java.util.List;
public class Dosage
{
private String id;
private String packed;
private List<Medicine> medicine;
public void setId(String id){
this.id = id;
}
public String getId(){
return this.id;
}
public void setPacked(String packed){
this.packed = packed;
}
public String getPacked(){
return this.packed;
}
public void setMedicine(List<Medicine> medicine){
this.medicine = medicine;
}
public List<Medicine> getMedicine(){
return this.medicine;
}
}
import java.util.ArrayList;
import java.util.List;
public class Band
{
private String name;
private List<Dosage> dosage;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setDosage(List<Dosage> dosage){
this.dosage = dosage;
}
public List<Dosage> getDosage(){
return this.dosage;
}
}
import java.util.ArrayList;
import java.util.List;
public class Timeline
{
private DateTime Date;
private List<Band> band;
public void setDate(DateTime Date){
this.Date = Date;
}
public DateTime getDate(){
return this.Date;
}
public void setBand(List<Band> band){
this.band = band;
}
public List<Band> getBand(){
return this.band;
}
}
public class Root
{
private boolean error;
private Timeline Timeline;
public void setError(boolean error){
this.error = error;
}
public boolean getError(){
return this.error;
}
public void setTimeline(Timeline Timeline){
this.Timeline = Timeline;
}
public Timeline getTimeline(){
return this.Timeline;
}
}
...enjoy...
For first question:
You can parse JSON without POJO classes but it is recommended to use
them and About you are stucking about generating them from the JSON
you can use jsonschema2pojo I think
it is the best.
And for the second one:
Yest there are standards for JSON you can find them in JSON website.
Step 1 : First start with the inner most json object which I can see is "medicine"
Create a POJO class something like this
public class Medicine implements android.os.Parcelable {
#SerializedName("id")
private String id;
// Getter setter method for id
// Do it for all the JSON tags
}
Step 2 : Create a class for "medicineList" this will somewhat be like this
public class MedicineList implements Parcelable {
#SerializedName("medicineList")
private List<Medicine > medicine;
// Getter setter can go here
}
In the similar fashion just move outside to your base tag in JSON response. This make things pretty easy for me to understand. I am not posting to the complete solution as thats your homework at EOD.
the solution for Q1 -
Yes, you can parse above response using model classes by installing the DTO plugin in the Android Studio. The plugin will automatically create the POJO class for the response.
I am trying to read some values under "properties" of following JSON string to a POJO. But all I get is null values.
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
144.9798,
-37.743
]
},
"properties": {
"PFI": "51351644",
"EZI_ADD": "581 BELL STREET COBURG 3058",
"ROAD_NAME": "BELL",
"ROAD_TYPE": "STREET",
"LOCALITY": "COBURG",
"LGA_CODE": "316",
"STATE": "VIC",
"POSTCODE": "3058",
"ADD_CLASS": "S"
},
"id": "ADDRESS.581"
}
My POJO class
#JsonIgnoreProperties(ignoreUnknown = true)
class Property {
public Property(){}
private String EZI_ADD; // e.g., "14 FAIRWAY COURT BUNDOORA 3083"
private String STATE; // e.g., "VIC"
private String POSTCODE; // e.g., "3083"
private String LGA_CODE; // e.g., 373
private String LOCALITY; // e.g., "BUNDOORA"
private String ADD_CLASS; // e.g., "S", or "M"
private String SA1_7DIG11 = ""; // SA1 code e.g., "2120241"
public String getEZI_ADD() {
return EZI_ADD;
}
#JsonProperty("EZI_ADD")
public void setEZI_ADD(String eZI_ADD) {
EZI_ADD = eZI_ADD;
}
public String getSTATE() {
return STATE;
}
#JsonProperty("STATE")
public void setSTATE(String sTATE) {
STATE = sTATE;
}
public String getPOSTCODE() {
return POSTCODE;
}
#JsonProperty("POSTCODE")
public void setPOSTCODE(String pOSTCODE) {
POSTCODE = pOSTCODE;
}
public String getLGA_CODE() {
return LGA_CODE;
}
#JsonProperty("LGA_CODE")
public void setLGA_CODE(String lGA_CODE) {
LGA_CODE = lGA_CODE;
}
public String getLOCALITY() {
return LOCALITY;
}
#JsonProperty("LOCALITY")
public void setLOCALITY(String lOCALITY) {
LOCALITY = lOCALITY;
}
public String getADD_CLASS() {
return ADD_CLASS;
}
#JsonProperty("ADD_CLASS")
public void setADD_CLASS(String aDD_CLASS) {
ADD_CLASS = aDD_CLASS;
}
public String getSA1_7DIG11() {
return SA1_7DIG11;
}
#JsonProperty("SA1_7DIG11")
public void setSA1_7DIG11(String sA1_7DIG11) {
SA1_7DIG11 = sA1_7DIG11;
}
}
Conversion code is as follows
//Above json string
String jsonString = "{\"type\":\"Feature\",\"geometry\":{\"type\":\"Point\",\"coordinates\":[144.9798,-37.743]},\"properties\":{\"PFI\":\"51351644\",\"EZI_ADD\":\"581 BELL STREET COBURG 3058\",\"ROAD_NAME\":\"BELL\",\"ROAD_TYPE\":\"STREET\",\"LOCALITY\":\"COBURG\",\"LGA_CODE\":\"316\",\"STATE\":\"VIC\",\"POSTCODE\":\"3058\",\"ADD_CLASS\":\"S\"},\"id\":\"ADDRESS.581\"}";
ObjectMapper mapper = new ObjectMapper();
Property properties = mapper.readValue(jsonString, Property.class);
Output:
{
"properties": {
"EZI_ADD": null,
"STATE": null,
"POSTCODE": null,
"LGA_CODE": null,
"LOCALITY": null,
"ADD_CLASS": null,
"SA1_7DIG11": ""
}
}
The JSON String you're sending does not match the Property class. Add a wrapper class, e.g. something like this:
public class Feature {
private String type;
private String id;
private Property property;
// getters and setters
}
Then you can send the request and the JSON String will be parsed to your object:
{
"type": "feature",
"id": "test",
"property": {
"PFI": "51351644",
"EZI_ADD": "581 BELL STREET COBURG 3058",
"ROAD_NAME": "BELL",
"ROAD_TYPE": "STREET",
"LOCALITY": "COBURG",
"LGA_CODE": "316",
"STATE": "VIC",
"POSTCODE": "3058",
"ADD_CLASS": "S"
}
}
I am trying to convert JSON objects to POJO's with GSON.
JSON String
[
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
},
{
"automation_project": {
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
}
]
The AutomationProjectsList class used with GSON
public class AutomationProjectsList {
private List<AutomationProject> automationProject = new ArrayList<AutomationProject>();
public List<AutomationProject> getAutomationProject() {
return automationProject;
}
public void setAutomationProject(List<AutomationProject> automationProject) {
this.automationProject = automationProject;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automationProject
+ "]";
}}
Automation Project POJO
public class AutomationProject {
private Object userId;
private Integer groupId;
private Integer id;
private String name;
private String updatedAt;
private String createdAt;
public Object getUserId() {
return userId;
}
public void setUserId(Object userId) {
this.userId = userId;
}
public Integer getGroupId() {
return groupId;
}
public void setGroupId(Integer groupId) {
this.groupId = groupId;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(String updatedAt) {
this.updatedAt = updatedAt;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}}
The code I'm using
JSONArray jsonArray = new JSONArray(response.getEntity(String.class));
for(int i = 0; i < jsonArray.length(); i++){
if(jsonArray.get(i) instanceof JSONObject){
JSONObject jsnObj = (JSONObject)jsonArray.get(i);
AutomationProjectsList obj = new Gson().fromJson(jsnObj.toString(), AutomationProjectsList.class);
System.out.println(obj.getAutomationProject().get(0).getId());
}
}
But it gives an exception :
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at br.usp.icmc.teste.ConnectionRestClient.getBrowserStackProjects(ConnectionRestClient.java:74)
at br.usp.icmc.teste.TestePrincipal.main(TestePrincipal.java:9)
Why am I receiving an IndexOutOfBoundsException exception? Where am I wrong?
Your class or your JSON are incorrect. I'd suggest your JSON is.
A JSON matching your POJO class would be:
{
"automationProjects":[
{
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
},
{
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
]
}
Notice I used the name automationProjects for the list as it makes more sense, so your class would be:
public class AutomationProjectsList {
private List<AutomationProject> automationProjects = new ArrayList<AutomationProject>();
public List<AutomationProject> getAutomationProjects() {
return automationProjects;
}
public void setAutomationProjects(List<AutomationProject> automationProjects) {
this.automationProjects = automationProjects;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automationProject
+ "]";
}
}
And finally to convert JSON to AutomationProjectsList object:
AutomationProjectsList projectsList = new Gson().fromJson(jsonArray.toString(), AutomationProjectsList.class);
Then if you want to log each project:
for(AutomationProject project : projectsList.automationProjects){
System.out.println(porject.getId());
}
In conclusion, your code seems to have the fallowing issues:
Do you have a list of lists or just a single list of projects? If the list is just one, why do you iterate jsonArray like its sub-objects are lists themselves?
If you model your class correctly on the JSON then you don't need to iterate the JSON to obtain your objects
The JSON you posted is quite weird and uneasy to use with Gson, is it a requirement or can you edit it as you please?
Hope this helps
EDIT
Since you stated you cannot change the JSON you get, then it gets a little more complex, but everything is up to modelling the classes on the JSON format. So let's start form this JSON:
[
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
},
{
"automation_project": {
"user_id": null,
"name": "newintropage",
"updated_at": "2015-06-16T21:20:47Z",
"group_id": 764496,
"created_at": "2015-06-16T20:39:04Z",
"id": 29501
}
}
]
Now, this is quite nasty, but let's see what we have here: we have an unnamed array of objects with a single attribute "automationProject" which is our actual AutomationProject Object. So in terms of structure, it is a list of objects which wrap an actual AutomationProject.
Thus you'll need to get rid of your AutomationProjectList and change it with the more meaningful AutomationProjectWrapper looking as fallows:
public class AutomationProjectsWrapper {
private AutomationProject automation_project = new AutomationProject();
public AutomationProject getAutomationProject() {
return automation_project;
}
public void setAutomationProject(AutomationProject automationProject) {
this.automation_project = automationProject;
}
#Override
public String toString() {
return "AutomationProjectsList [automationProject=" + automation_project
+ "]";
}
}
See this class is equivalent to the JSON Object:
{
"automation_project": {
"user_id": null,
"name": "Untitled Project",
"updated_at": "2015-06-16T19:39:42Z",
"group_id": 764496,
"created_at": "2014-11-23T01:01:59Z",
"id": 16214
}
}
Finally you'll have an array of such wrapper objects as your jsonArray so you can write:
AutomationProjectWrapper[] projectsList = new Gson().fromJson(jsonArray.toString(), AutomationProjectWrapper[].class);
Then to log your objects:
for(AutomationProjectWrapper wrapper : projectsList){
System.out.println(wrapper.getAutomationProject().getId());
}
EDIT 2
Sorry for the mistake, in AutomationProjectWrapper class the AutomationProject field should be named automation_project.
Fixed in code above.
According to your JSON String the value you are trying to access is :
jsonString[i].automation_project.user_id
In your code you have: obj.getAutomationProject().get(0).getId()
I think is should be: obj[i].getAutomationProject().getId()