I am using Gson to get convert the object to json string, and its working fine but when I am sending that json to a webservice method using post, I have to add the post method's parameter name in the string.
Example:
jsonString I get from Gson new Gson().toJson(requestDataDTO) :
{
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
jsonString I want :
{
"requestDataDTO": {
"req": {
"AppId": "2",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
},
"req1": {
"AppId": "-33",
"ThirdParty": "3",
"UserId": "1",
"UserToken": "4"
}
}
}
for now I am adding this "requestDataDTO" string at the start of json string I got from Gson.
is there a way to achieve this ?
Assuming you have an object which looks somehow like this:
package com.dominikangerer.q25077756;
import com.google.gson.annotations.SerializedName;
public class RequestDataDTO {
// {"AppId":"2","ThirdParty":"3","UserId":"1","UserToken":"4"}
#SerializedName("AppId")
private String appId;
#SerializedName("ThirdParty")
private String thirdParty;
#SerializedName("UserId")
private String userId;
#SerializedName("UserToken")
private String userToken;
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getThirdParty() {
return thirdParty;
}
public void setThirdParty(String thirdParty) {
this.thirdParty = thirdParty;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserToken() {
return userToken;
}
public void setUserToken(String userToken) {
this.userToken = userToken;
}
}
The easiest and also for me most readable solution would be to create an wrapper/container Class which contains a HashMap (key/value) like this:
package com.dominikangerer.q25077756;
import java.util.HashMap;
public class RequestDataDTOContainer {
private HashMap<String, RequestDataDTO> requestDataDTO = new HashMap<String, RequestDataDTO>();
public HashMap<String, RequestDataDTO> getRequestDataDTO() {
return requestDataDTO;
}
public void setRequestDataDTO(HashMap<String, RequestDataDTO> requestDataDTO) {
this.requestDataDTO = requestDataDTO;
}
public void putRequestDataDTO(String key, RequestDataDTO value){
this.requestDataDTO.put(key, value);
}
}
To run it simply test it with a main like this:
// enable pretty printing
Gson gson = new GsonBuilder().setPrettyPrinting().create();
// too lazy to fill the objects by hand
String reqJson = "{\"AppId\":\"2\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
String req1Json = "{\"AppId\":\"-33\",\"ThirdParty\":\"3\",\"UserId\":\"1\",\"UserToken\":\"4\"}";
// deserialize it with gson
RequestDataDTO req = gson.fromJson(reqJson, RequestDataDTO.class);
RequestDataDTO req1 = gson.fromJson(req1Json, RequestDataDTO.class);
// initiliaze the container
RequestDataDTOContainer container = new RequestDataDTOContainer();
// adding the 2 req objects with the certain key
container.putRequestDataDTO("req", req);
container.putRequestDataDTO("req1", req1);
// Print it as pretty json
System.out.println(gson.toJson(container));
You are now more flexibility if you want to add more meta information like a whole meta object or similar without adding a hardcoded String to that json.
You can find the whole Example in this github repository: Java Stackoverflow Answers by DominikAngerer
Related
I would like to unmarshal a list of players from this nested json using retrofit 2 and Gson in android:
{
"api": {
"status": 200,
"message": "GET players/playerId/44",
"results": 1,
"filters": [
...
],
"players": [
{
"firstName": "Kent",
"lastName": "Bazemore",
"teamId": "29",
"yearsPro": "7",
"collegeName": "Old Dominion",
"leagues": {
"standard": {
"jersey": "24",
"active": "1",
"pos": "G-F"
}
}
}
]
}
}
Can anyone help?
If you are using Retrofit, I would advise you to look into Gson/Jackson/Moshi converters. These help in converting your JSON responses to plain Java objects.
You should then be able to access it as
api.getPlayers() -> array of players
You first need to create a model class then you can access the particular key. For example:
public class ResponseItem {
private int status;
private String message;
private List<String> players;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<String> getPlayers() {
return players;
}
public void setPlayers(List<String> players) {
this.players = players;
}
Add the following code snippet in your retrofit method:
if (response.isSuccessful()) {
ResponseItem responseItem;
responseItem = response.body();
}
P.S. Make sure to complete the model class using the same pattern.
I am struggling to deserialise complex nested Json data into Java objects I think my class structure is wrong. Here is my Json data:
{
"resultsPerPage": 20,
"startIndex": 0,
"totalResults": 2,
"result": {
"dataType": "CPE",
"feedVersion": "1.0",
"cpeCount": 2,
"feedTimestamp": "2021-03-19T13:06",
"cpes": [
{
"deprecated": false,
"cpe23Uri": "cpe:2.3:o:microsoft:windows_10:1511:*:*:*:*:*:x64:*",
"lastModifiedDate": "2015-12-09T17:28Z",
"titles": [
{
"title": "Microsoft Windows 10 1511 64-bit",
"lang": "en_US"
}
],
"refs": [
{
"ref": "https://www.microsoft.com/en-us/",
"type": "Vendor"
}
],
"deprecatedBy": [],
"vulnerabilities": [
"CVE-2016-0174",
"CVE-2016-0171"
]
}
Here is the class I map the Json data to:
public class RESPONSE {
Result result;
}
class Result {
List<Cpes> cpes;
}
class Cpes {
String cpe23Uri;
List<Titles> titles;
List<String> vulnerabilities;
}
class Titles{
String title;
}
When I debug my code r in the below code is null and I think it's because my RESPONSE class isn't set up right.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
RESPONSE r = mapper.readValue(response.getContent(), RESPONSE.class);
System.out.println(r);
Your object model should match the structure of the JSON you are trying to read. For example, it'll have to look something like the following:
public class Response {
private int resultsPerPage;
private int startIndex;
private int totalResults;
private Result result;
// Should include getters and setters
}
public class Result {
private String dataType;
private String feedVersion;
private int cpeCount;
private String feedTimestamp;
private CPE[] cpes;
// Should include getters and setters
}
public class CPE {
private boolean deprecated;
private String cpe23Uri;
private String lastModifiedDate;
private Title[] titles;
private Ref[] refs;
private String[] deprecatedBy;
private String[] vulnerabilities;
// Should include getters and setters
}
public class Title {
private String title;
private String lang;
// Should include getters and setters
}
public class Ref {
private String ref;
private String type;
// Should include getters and setters
}
Note that to keep the code sample short, I've omitted the getters and setters.
Edit: As Tugrul pointed out below, since fail on unknown property is disabled, it won't fail if there are missing fields in your model. The only issue is the missing getters and setters.
I also found another way to solve this issue for future reference.
I used a tree data structure to access my Json fields which means I can just declare a flat class:
public class Test {
private String cpe23Uri;
private String title;
private List<String> vulnerabilities;
public String getCpe23Uri() {
return cpe23Uri;
}
public void setCpe23Uri(String cpe23Uri) {
this.cpe23Uri = cpe23Uri;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<String> getVulnerabilities() {
return vulnerabilities;
}
public void setVulnerabilities(List<String> vulnerabilities) {
this.vulnerabilities = vulnerabilities;
}
}
I then mapped using a Tree
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
JsonNode resultNode = mapper.readTree(response.getContent());
Test t = new Test();
t.setCpe23Uri(resultNode.get("result").get("cpes").get(0).get("cpe23Uri").textValue());
I have an API built in Java Spring that return (using JacksonJaxbJsonProvider 2.5.5) a JSON object from this class:
public class FieldValues {
private String code;
private Object value;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
In the main object I've
#JsonRootName(value = "WorkRequest")
#XmlRootElement(name = "WorkRequest")
#JsonIgnoreProperties(ignoreUnknown = true)
public class WorkRequestDTOResponse {
private List<FieldValues> fieldValues;
public List<FieldValues> getFieldValues() {
return fieldValues;
}
public void setFieldValues(List<FieldValues> fieldValues) {
this.fieldValues = fieldValues;
}
}
But the output of the fieldValues object is this:
"fieldValues": [
{
"code": "anomaly",
"value": {
"#xsi.type": "ns3:boolean",
"$": "true"
}
},{
"code": "internal_note",
"value": {
"#xsi.type": "ns3:string",
"$": "Test text example"
}
}
]
instead what I need is this:
"fieldValues": [
{
"code": "anomaly",
"value": true
},{
"code": "internal_note",
"value": "Test text example"
}
]
This is my JSON Provider:
public class ErmesJSONProvider extends JacksonJaxbJsonProvider {
public ErmesJSONProvider() {
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
mapper.configure(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED, false);
_mapperConfig.setMapper(mapper);
_mapperConfig.getConfiguredMapper().setAnnotationIntrospector(new JacksonAnnotationIntrospector());
}
}
Trying to use a String instead an object:
public class FieldValues {
private String code;
private String value;
But if I set this value as String fieldValues.setValue("true"), the JSON output is "value": true instead "value": "true"
Likewise if I set this value as String but with an Integer fieldValues.setValue("1"), the JSON output is "value": 1 instead "value": "1"
If I print the return object using ObjectMapper I've the right JSON:
String payload = new ObjectMapper().writeValueAsString(requestResult)
but if I return a Response like this:
return Response.status(Response.Status.CREATED).entity(new GenericEntity<RequestResult>(requestResult){}).build()
it return the wrong JSON.
I can't understand why 😥
Someone can help me? Thanks.
I want to parse the json string and form a pojo object but the response is somewhat unusual.
I have folloing type of response from API
"data": {
"12": {
"value": "$0.00",
"order_id": "12",
"order_date": "2020-08-26 15:50:05",
"category_name": "Games",
"brand_id": "4",
"denomination_name": "AED 50",
"order_quantity": "1",
"vendor_order_id": "A-123",
"vendor_location": "",
"vouchers": {
"804873": {
"pin_code": "41110AE",
"serial_number": "fddfgfgf1234444"
}
}
},
"15": {
"value": "$0.00",
"order_id": "15",
"order_date": "2020-08-26 08:39:11",
"category_name": "Games",
"brand_id": "52",
"brand_name": "PlayStation",
"denomination_name": "$20",
"order_quantity": "1",
"vendor_order_id": "A-316",
"vendor_location": "",
"vouchers": {
"806328": {
"pin_code": "fdfd",
"serial_number": "fawwwww"
}
}
}
}
}
How do I parse this response since inside data the field name is order id same with voucher
If you use Jackson JSON library, you should have POJOs like those shown below and use PropertyNamingStrategy.SnakeCaseStrategy to handle property names in the input JSON:
// top-level container
public class Response {
private Map<Integer, Order> data;
// getter/setter
}
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class Order {
private String value; // may be some Currency class
private Integer orderId;
#JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime orderDate;
private String categoryName;
private Integer brandId;
private String brandName;
private String denominationName; // may be Currency too
private Integer orderQuantity;
private String vendorOrderId;
private String vendorLocation;
private Map<Integer, Voucher> vouchers;
// getters/setters
}
#JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
public class Voucher {
private String pinCode;
private String serialNumber;
// getters/setters
}
I am sending json from ajax to controller that contain multiple array.
Json Data:
{
"node": [
{
"id": "dev_1",
"blockId": "11"
},
{
"id": "dev_2",
"blockId": "15"
}
],
"connect": [
{
"id": "con_5",
"typeId": "2"
}
],
"name": "test"
}
Controller:
#RequestMapping(value = "/saveBoard", method = RequestMethod.POST)
public JsonResponse saveBoard(#RequestBody String jsonData) throws IOException {
JsonResponse response = new JsonResponse();
ObjectMapper mapper = new ObjectMapper();
final JsonNode jsonNode = mapper.readTree(jsonData).get("node");
if(jsonNode.isArray()) {
for (final JsonNode nodes : jsonNode) {
System.out.println("jsonNode : "+ nodes);
}
}
return response;
}
I have tried with object mapper but not succeed.
Here i want to read different array for different classes like node for node class with some specified fields, connect for connect class and string for another use.
UPDATE
Contorller:
#RequestMapping(value = "/saveBoard", method = RequestMethod.POST)
public JsonResponse saveMissionBoard(#RequestBody MissionJsonPojo chartJson) {
boolean status = false;
String messsage = "";
JsonResponse response = new JsonResponse();
System.out.println("data : " + flowChartJson.getNodes());
return response;
}
Ajax:
$.ajax({
url: '<c:url value="/board/saveBoard"/>',
type: 'POST',
data: JSON.stringify(chartJson),
dataType: "json",
contentType: "application/json",
success: function(response) {
console.log("In success");
},
error: function (a, b, c) { }
});
JSON:
{
"nodes": [
{
"missionDeviceId": "device_1",
"device": "1",
"deviceXCoordinate": 79,
"deviceYCoordinate": 73,
"blockId": "1##1"
},
{
"missionDeviceId": "device_2",
"device": "3",
"deviceXCoordinate": 340,
"deviceYCoordinate": 146,
"blockId": "2##5"
}
],
"connections": [
{
"missionConnectionId": "con_5",
"sourceId": "device_1",
"targetId": "device_2",
"device": "2"
}
],
"name": "test"
}
Node Pojo:
public class Nodes{
private String missionDeviceId;
private Integer device;
private String deviceXCoordinate;
private String deviceYCoordinate;
private String blockId; //getters setters
}
Connection Pojo:
public class Connections{
private String missionConnectionId;
private String sourceId;
private String targetId;
private Integer device; //getters and setters
}
MissionJsonPojo:
public class MissionJsonPojo{
private List<Nodes> nodes;
private List<Connections> connections;
private String name; //getters and setters
}
As suggested by #dambros, create a POJO structure like this:
public class Node {
private String id;
private String blockId;
//setter-getters.
}
public class Connect {
private String id;
private String typeId;
//setter-getters.
}
import java.util.List;
public class Payload {
private List<Node> nodes;
private List<Connect> connects;
private String name;
//setter-getters
}
And change your method signature to:
public JsonResponse saveBoard(#RequestBody Payload payload) throws IOException {
}
This should solve your problem.