I am sending the following request (using Spring Boot)
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
response is the json object(i have ommitted lot of fields in json object)
{
"customer": {
"id": 100,
"ci": {
"lDb": "11",
"localId": "1"
},
"cusdata": {},
"rating": {
"id": 3140,
"dateTime": "2019-09-21 06:45:41.10",
"rawData": {
"seg": "XYZ",
"seg2": "XYZ",
"et": "XYZ_CORP",
"CountryCodes": [
"IN"
],
"doBusiness": "2017-09-20"
],
...
....
...
...
"status": "SUCCESS"
}
I need to map the below fields to a Pojo Class
1.localId
2.seg
3.seg2
4.status
How can i create the PojoClass such that those fields are mapped automatically
So basically how will my PojoClass should look like?
ResponseEntity<PojoClass> response = restTemplate.exchange(url, HttpMethod.GET, request, PojoClass.class);
I suggest that you use sites like http://www.jsonschema2pojo.org/. There, you can select many options on the right panel and adjust POJO you want to get from JSON schema.
Your PojoClass has to follow the structure of the JSON that your are receiving and have the fields that your are interested (or all of them).
For the first level class:
public class PojoClass {
private Customer customer;
private String status;
...
}
Then, create a Customer class for the customer fields and create more classes for the rest of the fields:
public class Customer {
public String id;
public CI ci;
public CustData custData;
...
}
Create a custom class PojoClass
public class PojoClass {
private Integer id;
private Object ci;
private Object cusdata;
private Object rating;
private Object status;
}
ResponseEntity<PojoClass> responseEntity = restTemplate.exchange(url,HttpMethod.GET,request,new ParameterizedTypeReference<PojoClass>(){
});
Related
I am trying to map my incoming json payload to an arraylist of my model class.
I have a solution but its unintuitive.
I try to do this but get compilation errors-
ObjectMapper mapper = new ObjectMapper();
ArrayList<ModelClass> = mapper.readValue(items, RoleAttribute.class);
FYI I am trying to save this data in a Mongo collection.
Controller-
#PostMapping(value="/resource", consumes="application/json")
public Iterable<ModeClass> createResources(#RequestBody JSONObject requestBody ) throws JsonParseException, JsonMappingException, IOException {
System.out.println(requestBody.getClass());
return serviceImpl.saveResources(requestBody);
}
Model class-
#Data
#AllArgsConstructor
#Document(collection="collection-name")
public
class ModelClass{
#Field
private String ID;
#Field
private String description;
}
The payload is coming in the following format-
{
"data": [
{
"ID": "1",
"description": "desc1"
},
{
"ID": "2",
"description": "desc2"
},
{
"ID": "3",
"description": "desc3"
},
{
"ID": "4",
"description": "desc4"
}
....
]
}
I know I should be using jackson but I can't seem to figure this out. Do I need to change my POJO? Do I need to create custom Jackson config?
You can do it with json annotation. I also notice that your values are represented as data in json so that also needs to be taken care of. Look at below code. That will solve your problem.
import com.fasterxml.jackson.annotation.JsonProperty;
#Data
#AllArgsConstructor
#Document(collection="collection-name")
public class ModelClass{
#Field
#JsonProperty("ID")
private String classID;
#Field
#JsonProperty("description")
private String classDescription;
public String getClassID() {
return classID;
}
public void setClassID(String classID) {
this.classID = classID;
}
public String getClassDescription() {
return classDescription;
}
public void setClassDescription(String classDescription) {
this.classDescription = classDescription;
}
}
And wrapper Data class as below
class Data {
ModelClass[] data;
public ModelClass[] getData() {
return data;
}
public void setData(ModelClass[] data) {
this.data = data;
}
}
And json conversion code as below
ObjectMapper mapper = new ObjectMapper();
// json is your incoming json as a string. You can put inputstream also
Data values = mapper.readValue(json, Data.class);
System.out.println(values.getData().length);
System.out.println(values.getData()[0].getClassID());
You would need a container class for the data field, something like:
#Data
#Document(collection="collection-name")
public class DataClass{
private List<ModelClass> data;
}
Doing it via Jackson should be automatic this way, in controller:
public Iterable<ModeClass> createResources(#RequestBody DataClass requestBody ) {
is there anyway to correct Map method responses which use generics as response subfields with the appropriate implementation? Example:
Let's say I have a generic response class:
public class Response {
private String createdOn;
//other fields
private Map<String, Object> values;
private Model object;
//getters and setters
}
Generic model class:
public class Model{
}
Model Class A:
public class ModelA extends Model{
private String name;
private String lastname;
//getters and setters
}
And Model Class B:
public class ModelB extends Model{
private int number;
private boolean isTrue;
//getters and setters
}
And method doSomeStuff() which let's say returns a ResponseEntity< Response> where in this particular response "values" is a map< String, SomeRandomObject> and object is a ModelA object.
And suppose I have another method doSomeOtherStuff() which returns a ResponseEntity< Response> object where in that case "values" is a map< String, AnotherRandomObject> and object is a ModelB object.
Is there any way to map the response subfields of the first method to the appropriate ones? Using swagger-UI all I get is the following for both methods:
{
"createdOn": "string",
// other fields
"model": {},
"values": {}
}
Whereas I would like something like the following:
doSomeStuff():
{
"createdOn": "string",
// other fields
"model": {
"name": "string",
"lastname": "string",
}
"model": {
//All the subfields of SomeRandomObject
},
}
doSomeOtherStuff():
{
"createdOn": "string",
// other fields
"model": {
"number": "int",
"isTrue": "boolean",
}
"model": {
//All the subfields of AnotherRandomObject
},
}
Since it obviously cannot determine what type of objects are returned at the implementation level.
P.S. The above classes are as an example. I would really appreciate help to make the documentation work and not for ways to refactor it since the above logic is applied to more than 100 rest methods.
Edit: I am using springfox-swagger2 with springfox-swagger-ui.
First, thank you very much for reading this question.
I have a JPA project and everything works fine, the json that i get with the controller is of this form:
{"id": 1, "name": "Canada"},{"id": 2, "name": "USA"}
All its fine but i would like to get a json with the Jsend standard, it something like this:
{
status : "success",
data : {
"country" : [
{"id": 1, "name": "Canada"},
{"id": 2, "name": "USA"}
]
}
}
{
"status" : "fail",
"data" : { "title" : "A title is required" }
}
{
"status" : "error",
"message" : "Unable to communicate with database"
}
As you can see i want to have a status that says success, fail or error:
But i dont know how to do it. This is my DTO, DAO and Controller
#Entity
public class Country implements Serializable {
private static final long serialVersionUID = -7256468460105939L;
#Id
#Column(name="id")
private int id;
#Column(name="name")
private String name;
//Constructor, get and set
DAO
#Repository
#Transactional
public class CountryRepository {
#PersistenceContext
EntityManager entityManager;
public CountryDTO findById(int id) {
return entityManager.find(CountryDTO.class, id);
}
}
Controller
#RestController
public class CountryController {
#Autowired
CountryDTO repository;
#RequestMapping(value="api/country/{id}", method=RequestMethod.GET)
public #ResponseBody CountryDTO getByID(#PathVariable("id") int id){
return repository.findById(id);
}
}
Again thank you for your time.
Its very good question from my point of view. So I can give list of action items to achieve this.
You should aware of #ControllerAdvice annotation which is available in Spring.
By utilizing that you can play with your response object.
Then You should create your own Object which is similar to JSend. In my case, I have created JSendMessage class
public class JSendMessage {
String status;
String message;
Object data;
// Add getter and setter
}
Now you should map above class with your #ControllerAdvice return your required object.
So whenever there is a exception you can create and send your own custom exception message.
There will be lot of reference for this. Just look for #ControllerAdvice
I have a json response as below
{
"#odata.context": "some context value here",
"value": [{
"#odata.id": "odata id value1",
"#odata.etag": "W/\"CQEet/1EgOuA\"",
"Id": "id1",
"Subject": "subject1"
}, {
"#odata.id": "odata id value2",
"#odata.etag": "W/\"CyEet/1EgOEk1t/\"",
"Id": "id2",
"Subject": "subject2"
}]
}
How do I create a bean class(MyMessage) to parse the "value" using spring resttemplate?
RestTemplate rest = new RestTemplate();
ResponseEntity<MyMessage> response = rest.exchange(url, HttpMethod.GET, entity, MyMessage.class);
Could someone please help?
Annotate bean properties with #JsonProperty to set JSON field name for the property if it is different.
See:
JsonProperty annotation and When is the #JsonProperty property used and what is it used for?
Example (bean properties are public for example simplicity):
MyMessage class:
public class MyMessage {
#JsonProperty("#odata.context")
public String context;
#JsonProperty("value")
public Value[] values;
}
Value class:
// PascalCaseStrategy is to resolve Id and Subject properties
#JsonNaming(PascalCaseStrategy.class)
public class Value {
#JsonProperty("#odata.id")
public String odataId;
#JsonProperty("#odata.etag")
public String odataEtag;
public String id;
public String subject;
}
I need to send map of custom objects Map<String, Set<Result>> from frontend to backend.
So I think it should be possible to build JSON, send it to Controller via Ajax and receive it in Controller via #RequestBody annotation which should bind json to object. right?
Controller:
#RequestMapping(value = "/downloadReport", method = RequestMethod.POST)
public ResponseEntity<byte[]> getReport(#RequestBody Map<String, Set<Result>> resultMap)
{
Context context = new Context();
context.setVariable("resultMap", resultMap);
return createPDF("pdf-report", context);
}
JSON:
{
"result": [
{
"id": 1,
"item": {
"id": 3850,
"name": "iti"
},
"severity": "low",
"code": "A-M-01",
"row": 1,
"column": 1,
"description": "Miscellaneous warning"
}
]
}
Model:
public class Result {
private Integer id;
private Item item;
private String severity;
private String code;
private Integer row;
private Integer column;
private String description;
//getter & setters
//hashCode & equals
}
public class Item {
private Integer id;
private String name;
//getter & setters
}
After send such a JSON like above by ajax I am getting error message from browser:
The request sent by the client was syntactically incorrect
If I change JSON to send empty set like below then it works but of course my map has empty set:
{"result": []}
So, Why I am not able to receive filled map with set of objects? Why binding/unmarshalling do not work as expected and what I should do to make it works?
Note:
I am using Jackson library and marshalling for other case for #ResponseBody works fine. Problem is with unmarshalling and binding object via #RequestBody.
In order for jackson to properly deserialize your custom classes you need to provide #JsonCreator annotated constructor that follows one of the rules defined in the java doc. So for your Item class it could look like this:
#JsonCreator
public Item(#JsonProperty("id") Integer id,
#JsonProperty("name") String name) {
this.id = id;
this.name = name;
}
you have to deal with map differently,
first create wrapper class
public MyWrapperClass implements Serializable {
private static final long serialVersionUID = 1L;
Map<String, List<String>> fil = new HashMap<String, List<String>>();
// getters and setters
}
then you should take request in controller,
#PostMapping
public Map<String,List<String>> get(#RequestBody Filter filter){
System.out.println(filter);
}
Json Request should be like
{
"fil":{
"key":[
"value1",
"value2"
],
"key":[
"vakue1"
]
}
}