I have to send a batch of instructions in JSON data format as below:
{
"batchId": "123456",
"instructions": [ {
"instructionId": "1",
"customer": {
"iban": "abc",
"name": "abc"
}
},
"instructionId": "2",
"customer": {
"iban": "abc",
"name": "abc"
}
}
.
.
.
.. . . ..
]
}
Now, i will fetch multiple records/instructions from the database via query, which I will use to generate the JSON data-set as per the format above.
What I have researched: I have traversed many solutions and thought of my own that I shall create an object class of Instruction mapping with setters and getters. I shall use a loop through each record and set values of object fields from database via setter and add entry that complete object entry to JSON via getters.
I will continue this approach until the records are read completely.
My question is: Is this solution efficient and best one to deal with such requirement or any other suggestion?
Please suggest? Any sort of code snippet or help is appreciated.
You can use com.google.gson for that.
Create the Instruction object and then add the fields and annotate the field with SerializedName if you are mapping a different json name to your java field(E.g. instruction_id to instructionId).
import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.Map;
public class Instruction {
#SerializedName("instructionId")
private String instructionId;
#SerializedName("customer")
private List<Map<String, Object>> customer;
public String getInstructionId() {
return instructionId;
}
public void setInstructionId(String instructionId) {
this.instructionId = instructionId;
}
public List<Map<String, Object>> getCustomer() {
return customer;
}
public void setCustomer(List<Map<String, Object>> customer) {
this.customer = customer;
}
}
And then you can map your json to your instruction class.
Instruction instruction = new GsonBuilder()
.setPrettyPrinting()
.create()
.fromJson(json, Instruction.class);
Related
Say I have a JSON object representing an entity (can be any entity) like so:
{
"entity_id": "1",
"entity_name": "employee",
"entity_json": {
"employee_id": "e01",
"employee_name": "john",
"employee_phone_numbers": [
"1234567",
"8765433"
]
}
}
Note that entity_json can represent different entities having different structures as long as it is a valid JSON. For example, the following is another entity's representation:
{
"entity_id": "1",
"entity_name": "invoice",
"entity_json": {
"invoice_id": "1011",
"items": {
"item_id": "1",
"quantity": "3",
"price": "$100"
},
"date": "01-01-2020",
"customer": {
"id": "3",
"address": {
"street": "some_street",
"country": "CZ",
...
}
}
}
}
I want to be able to partially parse this JSON into an Entity POJO using Gson in Java. That is, I'll have an entity POJO like the one shown below:
public class Entity {
private String entity_id;
private String entity_name;
private String entity_json; // <-- entity_json is a String
// getters and setters
}
/*
* entity_json (for employee) = "{ \"employee_id\": \"1\", \"employee... }"
* entity_json (for invoice) = "{ \"invoice_id\": \"1011\", \"items... }"
*/
and I'm planning on performing any operation on entity_json using JsonPath.
Is there any way I can achieve this WITHOUT having to explicitly set entity_json in the JSON structure as a string with escapes?
Any help is appreciated here. Thanks!
You can avoid using a String for your entity_json by using Gson's JsonObject.
Here is my revised Entity class:
import com.google.gson.JsonObject;
public class MyEntity {
private String entity_id;
private String entity_name;
private JsonObject entity_json;
// getters and setters not shown
}
Then you can populate instances as follows:
MyEntity myEntityOne = new Gson().fromJson(JSON_ONE, MyEntity.class);
MyEntity myEntityTwo = new Gson().fromJson(JSON_TWO, MyEntity.class);
System.out.println(myEntityOne.getEntity_json());
System.out.println(myEntityTwo.getEntity_json());
In the above code, JSON_ONE and JSON_TWO are just strings containing the two sample JSONs from your question.
The console prints out the following (snipped for brevity):
{"employee_id":"e01","employee_name":"john","employee_phone_numbers":["1234567","8765433"]}
{"invoice_id":"1011","items":{"item_id":"1","quantity":"3","price":"$100"},"date":"01-01-2020"...
You can, of course, now use Gson to further manipulate each entity_json field as needed, since each one is itself a valid JSON object.
Here is my API Response, here the response is coming as Map object not Json.
{
"staticResponses": [
{
"code": {
"id": "someId",
"value": "44343567"
},
"staticAttributes": [
{
"id": "SEC_GUAR",
"value": "someValue4"
},
{
"id": "FIN_BOND_TYPE",
"value": ""
},
{
"id": "SEC_ISSER_ID",
"value": "someValue5"
},
{
"id": "SEC_ISSE_CRNCY",
"value": "someValue6"
}
//Here more objects with id and value(same as above) which needs to be mapped to corresponding fields of RatingModel Pojo.
]
}
]
}
API Response to equivalent Pojo field mapping
Keys Comming In API Response Corresponding Field Name in Model
SEC_GUAR guarantor
FIN_BOND_TYPE covered
SEC_ISSER_ID issuerId
SEC_ISSE_CRNCY securityCurrency
My Pojo to which I need to mapped the data
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class RatingCompositionModel implements CompositionModel {
private List<RatingModel> ratings;
}
RatingModel.java
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class RatingModel implements CompositionModel, Serializable {
private static final long serialVersionUID = -8447345872052120852L;
private String securityCurrency;
private String covered;
private String guarantor;
private String issuerId;
//here renaming fields
}
Code that I have written to achieve the same
private CompositionModel mapResponseToObject(LinkedHashMap responseBody) {
RatingCompositionModel ratingCompositionModel = new RatingCompositionModel();
List<RatingModel> ratingModelList = new ArrayList<>();
List<LinkedHashMap> responseObjectList = (List<LinkedHashMap>) responseBody.get("staticResponses");
if( null != responseObjectList && !responseObjectList.isEmpty() ) {
responseObjectList.forEach(responseObject -> {
List<LinkedHashMap> staticAttributes = (List<LinkedHashMap>)responseObject.get("staticAttributes");
if( null != staticAttributes && !staticAttributes.isEmpty()) {
RatingModel ratingModel = new RatingModel();
staticAttributes.forEach(staticAttribute -> {
if( ((String)staticAttribute.get("id")).equals("SEC_GUAR") ) {
ratingModel.setSecurityCurrency((String)staticAttribute.get("value"));
}
// more else if here...
});
ratingModelList.add(ratingModel);
}
});
}
ratingCompositionModel.setRatings(ratingModelList);
return ratingCompositionModel;
}
So here the problem is number of if-else block that I have to used,currently I have around 50 fields which I need to extract from the API Response and need to mapped to the corresponding fields in my POJO, so with my approach I have to use 50 if-else conditions and in future, if any change in my POJO like addition of some more fields(which has a high possibility) I have to add more if-else block.
Also worth noting here I cannot change the name of the fields in API response to match it with my POJO because this is some third party API not in my control.
Here looking for more dynamic solution to avoid if-else block as well to efficiently handle any future changes.
you don't need to have if-else conditions their, just iterate through staticAttributes and store them in a Map and once that is done, you can directly map this Map object to your POJO class using ObjectMapper's convertValue api.
FinalPojo readValue = objectMapper.convertValue(collect, FinalPojo.class);
But you would need to tell Jackson that which key in the map is to be mapped to what field in your POJO. And you can use #JsonProperty annotation for that.
Below is the sample POJO class
import com.fasterxml.jackson.annotation.JsonProperty;
public class FinalPojo {
#JsonProperty("SEC_GUAR")
private String guarantor;
#JsonProperty("FIN_BOND_TYPE")
private String covered;
#JsonProperty("SEC_ISSER_ID")
private String issuerId;
#JsonProperty("SEC_ISSE_CRNCY")
private String securityCurrency;
}
you can simply annotate the fields of the class with #SerializedName annotation given by Gson library. you can find an example below. Its really conveniet to use this librart to convert to/from json.
https://www.tutorialspoint.com/what-to-use-serializedname-annotation-using-gson-in-java
my first post here. I'm working on a API and i found a trouble that i don´t know how to solve it.
I´m trying to get the remaining stock of all products in my database. I´m using Spring boot and MongoDB with the Spring Data dependency.
Here is my code:
#GetMapping("/remaining-stock")
public ResponseEntity<List<Pair<String, Integer>>> showAllStock() throws EmptyDepositException{
List<Pair<String, Integer>> allStock;
try {
allStock = depServ.showAllStock();
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
When i do that GET request, this is the JSON i get:
[
{
"first": "Water",
"second": 5
},
{
"first": "Milk",
"second": 40
}
]
The values are OK but i want to rename the variables names with a better name like this:
[
{
"Product name": "Water",
"Remaining stock": 5
},
{
"Product name": "Milk",
"Remaining stock": 40
}
]
There is a way to do that?
Sorry for my english, i'm from Argentina so maybe something is not clear. I hope you can help me.
Thank you all in advance.
You can use #JsonProperty annotation which indicates that the field name is used as the property name without any modifications, but it can be specified to non-empty value to specify different name. Property name refers to name used externally, as the field name in JSON objects.
public class Product implements Serializable {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private long second;
// implement methods for getters and setters
}
With Pair Class, you can't do that. I suggest you to create a DTO class like below :
public class CustomPair {
#JsonProperty("Product name")
private String first;
#JsonProperty("Remaining stock")
private String second;
// standard getters and setters
}
Then your controller will be like this :
#GetMapping("/remaining-stock")
public ResponseEntity<List<CustomPair>> showAllStock() throws EmptyDepositException{
List<CustomPair> allStock;
try {
allStock = depServ.showAllStock(); // depServ.showAllStock(); should return List<CustomPair>
}catch(EmptyDepositException ex) {
allStock = null;
}
return ResponseEntity.ok(allStock);
}
I am fairly new to using JAX-RS and Jersey. The problem I am facing is that I cannot get a response in JSON the way I would like. I want a response that is something similar to the following:
{
"result": "success",
"car": {
"id": 42,
"name": "toyota",
"model": "camry"
}
}
So far I have a class named Car. It has 3 fields: id, name, and model with getters and setters. I get properly formatted JSON response of a single instance of a Car using the function whose return type is Car.
public Car getCarWithId(#PathParam("id") int id) {
return carService.getCarWithId(id);
}
This only gives me the following:
{
"id": 42,
"name": "toyota",
"model": "camry"
}
How can I get the response with the "result":"success". This will help me solve more complex problems in the future. Thanks for any help.
P.S. I thought about trying to return a hashmap but that gives me an error and seems like I would go into a deeper hole.
Assuming you're provider is Jackson, you could wrap it in a custom ResponseEntity object with a result field, along with a Map<String, Object> with the getter annotated with #JsonAnyGetter. For instance
public class ResponseEntity {
private String result;
private final Map<String, Object> otherFields = new HashMap<>();
public String getResult() {
return result;
}
#JsonAnyGetter
public Map<String, Object> getOtherFields() {
return otherFields;
}
public void addField(String field, Object value) {
otherFields.put(field, value);
}
}
What the #JsonAnyGetter does is make it so that the otherField is not serialized, but only the properties in the Map. You after you create the instance, and all entity.addField("car", carObject);, you will get your desired result.
I have code in my android project that correctly deserializes json into POJO's using gson. I wish to add some condtional acceptance checks (sanity checks) to the incoming json. For instance, with the data structure below, I wish for the gson parser to only add objects where the start date < end date. I know I could iterate through the list after it is populated to remove invalid items, but I was wondering if there was any way to reject the items on the fly. Any help would be appreciated.
Example JSON
{
"Items" : [
{
"Name" : "Example Name",
"Start" : "2010-10-16 10:00:00",
"End" : "2011-03-20 17:00:00",
<other fields>
},
<several more items>
]
}
ItemList.java
public class ItemList {
private List<ItemHeader> Items;
public void setItemHeaders(List<ItemHeader> headers) {
Items = headers;
}
public List<ItemHeader> getItemHeaders() {
return Items;
}
}
ItemHeader.java has fields for name, start, end and all the other fields.
You'd need to write your own deserializer and have it throw an exception when your condition isn't met.
http://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer
I don't know that you should do this, but it's possible.