How to parse a json with dynamic property name in java? - java

I need to consume and parse incoming json from a CRM system in my code. I used RestTemplate to do it. So the response from the CRM system looks like below.
{ "GvyArEFkg6JX6wI": {
"entityId": "GvyArEFkg6JX6wI",
"mergePolicy": {
"id": "9245a39d-fe1a-4b33-acab-9bc5cbabf37c"
}
}
}
Now the problem is the property name ("GvyArEFkg6JX6wI" in this case) in dynamic and in the next response it would be another string. In this case, how can I parse this json as this is not fixed? I tried using jsonGetter but it only wraps it around another block and still does not resolve the problem of parsing the response.
AdobeResponseDto.class
#Builder
#ToString
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
#NoArgsConstructor
public class AdobeResponseDto {
public Map<String, AdobeResponseFinal> adobeResponseWrapper = new HashMap<>();
#JsonAnySetter
public void setAdobeResponseWrapper(String name, AdobeResponseFinal value) {
adobeResponseWrapper.put(name, value);
}
#JsonAnyGetter
public Map<String, AdobeResponseFinal> getAdobeResponseWrapper() {
return adobeResponseWrapper;
}
}
AdobeResponseFinal.class
#Data
#Builder
#AllArgsConstructor
#NoArgsConstructor
public class AdobeResponseFinal {
public String entityId;
public MergePolicy mergePolicy;
}
I am calling the service like this:
final ResponseEntity<AdobeResponseDto> finalResponse;
finalResponse = aepClient.exchange(uri,HttpMethod.GET,entity,AdobeResponseDto.class);
final AdobeResponseDto body = finalResponse.getBody();
if(ObjectUtils.isNotEmpty(body)){
return body;
}
But in this way, the response I am getting is
{
"adobeResponseWrapper": {
"GvyArEFkg6JX6wI": {
"entityId": "GvyArEFkg6JX6wI",
"mergePolicy": {
"id": "9245a39d-fe1a-4b33-acab-9bc5cbabf37c"
}
}

If you just want to get the value of dynamic field name (e.g., "GvyArEFkg6JX6wI" in your case), you can just deserialize the response body to a Map and then traverse its value as follows:
ResponseEntity<String> finalResponse = aepClient.exchange(uri, HttpMethod.GET, entity, String.class);
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> result = objectMapper.readValue(finalResponse.getBody(), Map.class);
result.values().forEach(System.out::println);
Console output:
{entityId=GvyArEFkg6JX6wI, mergePolicy={id=9245a39d-fe1a-4b33-acab-9bc5cbabf37c}}
And if you want to deserialize the response body to your DTO (I assume that there is only ONE root-level property), you can modify the DTO like:
public class AdobeResponseDto {
private AdobeResponseFinal adobeResponseFinal;
#JsonAnySetter
public void setAdobeResponseFinal(String name, AdobeResponseFinal value) {
adobeResponseFinal = value;
}
#JsonAnyGetter
public AdobeResponseFinal getAdobeResponseFinal() {
return adobeResponseFinal;
}
}
Then you can get similar result as follows:
ResponseEntity<String> finalResponse = aepClient.exchange(uri, HttpMethod.GET, entity, String.class);
AdobeResponseDto adobeResponseDto = objectMapper.readValue(finalResponse.getBody(), AdobeResponseDto.class);
System.out.println(adobeResponseDto.getAdobeResponseFinal().toString());
Console output:
AdobeResponseFinal{entityId='GvyArEFkg6JX6wI', mergePolicy=MergePolicy{id='9245a39d-fe1a-4b33-acab-9bc5cbabf37c'}}

Related

How to get integer array from Java Object? [duplicate]

I have a sample RestController in Spring Boot:
#RestController
#RequestMapping("/api")
class MyRestController
{
#GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
I am using the JSON library org.json
When I hit API /hello, I get an exception saying :
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Request processing failed; nested exception is
java.lang.IllegalArgumentException: No converter found for return
value of type: class org.json.JSONObject] with root cause
java.lang.IllegalArgumentException: No converter found for return
value of type: class org.json.JSONObject
What is the issue? Can someone explain what exactly is happening?
As you are using Spring Boot web, Jackson dependency is implicit and we do not have to define explicitly. You can check for Jackson dependency in your pom.xml in the dependency hierarchy tab if using eclipse.
And as you have annotated with #RestController there is no need to do explicit json conversion. Just return a POJO and jackson serializer will take care of converting to json. It is equivalent to using #ResponseBody when used with #Controller. Rather than placing #ResponseBody on every controller method we place #RestController instead of vanilla #Controller and #ResponseBody by default is applied on all resources in that controller. Refer this link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
The problem you are facing is because the returned object(JSONObject) does not have getter for certain properties. And your intention is not to serialize this JSONObject but instead to serialize a POJO. So just return the POJO.
Refer this link: https://stackoverflow.com/a/35822500/5039001
If you want to return a json serialized string then just return the string. Spring will use StringHttpMessageConverter instead of JSON converter in this case.
The reason why your current approach doesn't work is because Jackson is used by default to serialize and to deserialize objects. However, it doesn't know how to serialize the JSONObject. If you want to create a dynamic JSON structure, you can use a Map, for example:
#GetMapping
public Map<String, String> sayHello() {
HashMap<String, String> map = new HashMap<>();
map.put("key", "value");
map.put("foo", "bar");
map.put("aa", "bb");
return map;
}
This will lead to the following JSON response:
{ "key": "value", "foo": "bar", "aa": "bb" }
This is a bit limited, since it may become a bit more difficult to add child objects. Jackson has its own mechanism though, using ObjectNode and ArrayNode. To use it, you have to autowire ObjectMapper in your service/controller. Then you can use:
#GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
This approach allows you to add child objects, arrays, and use all various types.
You can either return a response as String as suggested by #vagaasen or you can use ResponseEntity Object provided by Spring as below. By this way you can also return Http status code which is more helpful in webservice call.
#RestController
#RequestMapping("/api")
public class MyRestController
{
#GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> sayHello()
{
//Get data from service layer into entityList.
List<JSONObject> entities = new ArrayList<JSONObject>();
for (Entity n : entityList) {
JSONObject entity = new JSONObject();
entity.put("aa", "bb");
entities.add(entity);
}
return new ResponseEntity<Object>(entities, HttpStatus.OK);
}
}
you can also use a hashmap for this
#GetMapping
public Map<String, Object> get() {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
More correct create DTO for API queries, for example entityDTO:
Default response OK with list of entities:
#GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public List<EntityDto> getAll() {
return entityService.getAllEntities();
}
But if you need return different Map parameters you can use next two examples
2. For return one parameter like map:
#GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getOneParameterMap() {
return ResponseEntity.status(HttpStatus.CREATED).body(
Collections.singletonMap("key", "value"));
}
And if you need return map of some parameters(since Java 9):
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getSomeParameters() {
return ResponseEntity.status(HttpStatus.OK).body(Map.of(
"key-1", "value-1",
"key-2", "value-2",
"key-3", "value-3"));
}
#RequestMapping("/api/status")
public Map doSomething()
{
return Collections.singletonMap("status", myService.doSomething());
}
PS. Works only for 1 value
If you need to return a JSON object using a String, then the following should work:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
...
#RestController
#RequestMapping("/student")
public class StudentController {
#GetMapping
#RequestMapping("/")
public ResponseEntity<JsonNode> get() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}");
return ResponseEntity.ok(json);
}
...
}
use ResponseEntity<ResponseBean>
Here you can use ResponseBean or Any java bean as you like to return your api response and it is the best practice. I have used Enum for response. it will return status code and status message of API.
#GetMapping(path = "/login")
public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
loginService.login(username, password, request);
return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS,
HttpStatus.ACCEPTED);
}
for response ServiceStatus or(ResponseBody)
public enum ServiceStatus {
LOGIN_SUCCESS(0, "Login success"),
private final int id;
private final String message;
//Enum constructor
ServiceStatus(int id, String message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
}
Spring REST API should have below key in response
Status Code
Message
you will get final response below
{
"StatusCode" : "0",
"Message":"Login success"
}
you can use ResponseBody(java POJO, ENUM,etc..) as per your requirement.
I use to return Map<String,Object> in the Controller by using the toMap() method of org.json.JSONObject as follows.
#GetMapping("/json")
public Map<String, Object> getJsonOutput() {
JSONObject jsonObject = new JSONObject();
//construct jsonObject here
return jsonObject.toMap();
}
you can do this :
#RestController
#RequestMapping("/api")
class MyRestController
{
#GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}").toMap();;
}
}

How to get specific variable from JSON object?

I'm trying to get some data from other API and I need to get StatusCode from JSON object but I'm getting null object.
I was trying to create new class with StatusCode variable but I'm getting null.
I'm trying to get this data :
Data(data=[{"Number":"20450143160505","DateCreated":"11-06-2019 10:14:27","DocumentWeight":0.5,"CheckWeight":0,"SumBeforeCheckWeight":0,"PayerType":"Recipient","RecipientFullName":"","RecipientDateTime":"","ScheduledDeliveryDate":"12-06-2019","PaymentMethod":"Cash","CargoDescriptionString":"","CargoType":"Parcel","CitySender":"Сокільники","CityRecipient":"Київ","WarehouseRecipient":"Відділення №150 (до 30 кг): вул. Антоновича, 43 (м.\"Олімпійська\")","CounterpartyType":"PrivatePerson","Redelivery":1,"RedeliverySum":"","RedeliveryNum":"","RedeliveryPayer":"","AfterpaymentOnGoodsCost":"","ServiceType":"WarehouseWarehouse","UndeliveryReasonsSubtypeDescription":"","WarehouseRecipientNumber":150,"LastCreatedOnTheBasisNumber":"","LastCreatedOnTheBasisDocumentType":"","LastCreatedOnTheBasisPayerType":"","LastCreatedOnTheBasisDateTime":"","LastTransactionStatusGM":"","LastTransactionDateTimeGM":"","WarehouseRecipientInternetAddressRef":"916c7c93-8460-11e4-acce-0050568002cf","MarketplacePartnerToken":"","DateScan":"12:23 12.06.2019","ClientBarcode":"","SenderAddress":"","RecipientAddress":"","CounterpartySenderDescription":"","CounterpartyRecipientDescription":"","CounterpartySenderType":"Organization","PaymentStatus":"","PaymentStatusDate":"","AmountToPay":"","AmountPaid":"","WarehouseRecipientRef":"916c7c94-8460-11e4-acce-0050568002cf","DocumentCost":40,"AnnouncedPrice":"","OwnerDocumentNumber":"","DateFirstDayStorage":"2019-06-21","InternationalDeliveryType":"","DaysStorageCargo":"","RecipientWarehouseTypeRef":"841339c7-591a-42e2-8233-7a0a00f0ed6f","StorageAmount":"","StoragePrice":"","VolumeWeight":"0.50","SeatsAmount":"1","OwnerDocumentType":"","ActualDeliveryDate":"2019-06-12 12:23:22","DateReturnCargo":"","CardMaskedNumber":"","Status":"Прибув у відділення","StatusCode":"7","RefEW":"8ed817ef-8c18-11e9-91ff-0025b501a04b","RedeliveryPaymentCardRef":"","RedeliveryPaymentCardDescription":"","CreatedOnTheBasis":"","DatePayedKeeping":"2019-06-21 00:00:00","OnlineCreditStatusCode":"","OnlineCreditStatus":""}])
Method to get data :
RestTemplate restTemplate = new RestTemplate();
Data string = restTemplate.postForObject(blalba,blabla,Data.class)
And my class
public class Data {
#JsonProperty("data")
private JsonNode data;
//get set
}
There are a few ways to achieve it:
Using a Map<String, Object>
You could read the response payload as a Map<String, Object>:
ParameterizedTypeReference<HashMap<String, Object>> responseType =
new ParameterizedTypeReference<HashMap<String, Object>>() {};
Map<String, Object> responsePayload =
restTemplate.exchange(purchaseRequestDetailsEndpoint, HttpMethod.POST,
new HttpEntity<>(requestPayload), responseType);
String statusCode = responsePayload.get("StatusCode");
Mapping only the properties you need
Define a class mapping the properties you need:
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
public class ResponsePayload {
#JsonProperty("StatusCode")
private String statusCode;
}
And read the response payload using the class defined above:
ResponsePayload responsePayload =
restTemplate.postForObject(uri, request, ResponsePayload.class);
String statusCode = responsePayload.getStatusCode();
Alternatively you could map the properties you need and store the rest in a map:
#Data
public class ResponsePayload {
#JsonProperty("StatusCode")
private String statusCode;
#JsonAnySetter
private Map<String, Object> properties = new HashMap<>();
#JsonIgnore
public Object get(String key) {
return properties.get(key);
}
}

Map as parameter in RestAPI Post request

I have created an API with a Map<String, Integer> parameter, like this:
#RequestMapping(value = "upload", method = RequestMethod.POST)
public ResponseEntity<String> handleContactsFileUpload(#RequestParam("file") MultipartFile file,
#RequestParam("name") String name,
#RequestParam("campaignAppItemId") Long campaignAppItemId,
#RequestParam("fileColumnHeaders") Map<String,Integer> fileColumnHeaders) throws Exception {
if (file == null)
return new ResponseEntity<>("No file uploaded", HttpStatus.BAD_REQUEST);
contactService.handleContactsFile(file, name, campaignAppItemId,fileColumnHeaders);
return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
}
I am trying to call this via Postman:
I passed the fileColumnHeaders inside Body->Form Data as in the screenshot.
Then I got a message like this in Postman:
Failed to convert value of type 'java.lang.String' to required type 'java.util.Map'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Map': no matching editors or conversion strategy found.
Anybody know why this message came ?
How can we pass a map as a parameter in Rest API request?
How can we pass a map through Postman?
You could use #RequestBody instead of #RequestParam for Maps and other non trivial data types and objects - this way spring will map the JSON representing your map parameter to a domain object, which is then serializable and can be converted to a java object.
... Or simply create a converter:
#Component
#RequiredArgsConstructor
public class StringToMapConverter implements Converter<String, Map<String, Object>> {
private final ObjectMapper objectMapper;
#Override
public Map<String, Object> convert(String source) {
try {
return objectMapper.readValue(source, new TypeReference<Map<String, String>>() {
});
} catch (final IOException e) {
return null;
}
}
}
Firstly, you create DTO object to get all data from your request.
public class FormDataDTO {
private MultipartFile file;
private String name;
private Long campaignAppItemId;
private Map<String,Integer> fileColumnHeaders;
// getters, setters
}
Secondly, you can map FormDataDTO from your request without any annotation:
#RequestMapping(value = "upload", method = RequestMethod.POST)
public ResponseEntity<String> handleContactsFileUpload(FormDataDTO formDataDTO){
// your logic code here
}
Finally, form-data in your request will be:
I think this could work:
#RequestMapping(value = "upload/{fileColumnHeaders}", method = RequestMethod.POST)
public ResponseEntity<String> handleContactsFileUpload(#RequestParam("file") MultipartFile file,
#RequestParam("name") String name,
#RequestParam("campaignAppItemId") Long campaignAppItemId,
#MatrixVariable Map<String,Integer> fileColumnHeaders) throws Exception {
if (file == null)
return new ResponseEntity<>("No file uploaded", HttpStatus.BAD_REQUEST);
contactService.handleContactsFile(file, name, campaignAppItemId,fileColumnHeaders);
return new ResponseEntity<>("File uploaded successfully", HttpStatus.OK);
}
Put all other parameters into the body, but add the fileColumnHeaders to the URL like this:
/upload/firstName=1;lastName=2;address=3;phone=4
You will also need this extra configuration:
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
}

Returning JSON object as response in Spring Boot

I have a sample RestController in Spring Boot:
#RestController
#RequestMapping("/api")
class MyRestController
{
#GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
I am using the JSON library org.json
When I hit API /hello, I get an exception saying :
Servlet.service() for servlet [dispatcherServlet] in context with path
[] threw exception [Request processing failed; nested exception is
java.lang.IllegalArgumentException: No converter found for return
value of type: class org.json.JSONObject] with root cause
java.lang.IllegalArgumentException: No converter found for return
value of type: class org.json.JSONObject
What is the issue? Can someone explain what exactly is happening?
As you are using Spring Boot web, Jackson dependency is implicit and we do not have to define explicitly. You can check for Jackson dependency in your pom.xml in the dependency hierarchy tab if using eclipse.
And as you have annotated with #RestController there is no need to do explicit json conversion. Just return a POJO and jackson serializer will take care of converting to json. It is equivalent to using #ResponseBody when used with #Controller. Rather than placing #ResponseBody on every controller method we place #RestController instead of vanilla #Controller and #ResponseBody by default is applied on all resources in that controller. Refer this link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
The problem you are facing is because the returned object(JSONObject) does not have getter for certain properties. And your intention is not to serialize this JSONObject but instead to serialize a POJO. So just return the POJO.
Refer this link: https://stackoverflow.com/a/35822500/5039001
If you want to return a json serialized string then just return the string. Spring will use StringHttpMessageConverter instead of JSON converter in this case.
The reason why your current approach doesn't work is because Jackson is used by default to serialize and to deserialize objects. However, it doesn't know how to serialize the JSONObject. If you want to create a dynamic JSON structure, you can use a Map, for example:
#GetMapping
public Map<String, String> sayHello() {
HashMap<String, String> map = new HashMap<>();
map.put("key", "value");
map.put("foo", "bar");
map.put("aa", "bb");
return map;
}
This will lead to the following JSON response:
{ "key": "value", "foo": "bar", "aa": "bb" }
This is a bit limited, since it may become a bit more difficult to add child objects. Jackson has its own mechanism though, using ObjectNode and ArrayNode. To use it, you have to autowire ObjectMapper in your service/controller. Then you can use:
#GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
This approach allows you to add child objects, arrays, and use all various types.
You can either return a response as String as suggested by #vagaasen or you can use ResponseEntity Object provided by Spring as below. By this way you can also return Http status code which is more helpful in webservice call.
#RestController
#RequestMapping("/api")
public class MyRestController
{
#GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> sayHello()
{
//Get data from service layer into entityList.
List<JSONObject> entities = new ArrayList<JSONObject>();
for (Entity n : entityList) {
JSONObject entity = new JSONObject();
entity.put("aa", "bb");
entities.add(entity);
}
return new ResponseEntity<Object>(entities, HttpStatus.OK);
}
}
you can also use a hashmap for this
#GetMapping
public Map<String, Object> get() {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
More correct create DTO for API queries, for example entityDTO:
Default response OK with list of entities:
#GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
#ResponseStatus(HttpStatus.OK)
public List<EntityDto> getAll() {
return entityService.getAllEntities();
}
But if you need return different Map parameters you can use next two examples
2. For return one parameter like map:
#GetMapping(produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getOneParameterMap() {
return ResponseEntity.status(HttpStatus.CREATED).body(
Collections.singletonMap("key", "value"));
}
And if you need return map of some parameters(since Java 9):
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> getSomeParameters() {
return ResponseEntity.status(HttpStatus.OK).body(Map.of(
"key-1", "value-1",
"key-2", "value-2",
"key-3", "value-3"));
}
#RequestMapping("/api/status")
public Map doSomething()
{
return Collections.singletonMap("status", myService.doSomething());
}
PS. Works only for 1 value
If you need to return a JSON object using a String, then the following should work:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.ResponseEntity;
...
#RestController
#RequestMapping("/student")
public class StudentController {
#GetMapping
#RequestMapping("/")
public ResponseEntity<JsonNode> get() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}");
return ResponseEntity.ok(json);
}
...
}
use ResponseEntity<ResponseBean>
Here you can use ResponseBean or Any java bean as you like to return your api response and it is the best practice. I have used Enum for response. it will return status code and status message of API.
#GetMapping(path = "/login")
public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request,
HttpServletResponse response) {
String username = request.getParameter("username");
String password = request.getParameter("password");
loginService.login(username, password, request);
return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS,
HttpStatus.ACCEPTED);
}
for response ServiceStatus or(ResponseBody)
public enum ServiceStatus {
LOGIN_SUCCESS(0, "Login success"),
private final int id;
private final String message;
//Enum constructor
ServiceStatus(int id, String message) {
this.id = id;
this.message = message;
}
public int getId() {
return id;
}
public String getMessage() {
return message;
}
}
Spring REST API should have below key in response
Status Code
Message
you will get final response below
{
"StatusCode" : "0",
"Message":"Login success"
}
you can use ResponseBody(java POJO, ENUM,etc..) as per your requirement.
I use to return Map<String,Object> in the Controller by using the toMap() method of org.json.JSONObject as follows.
#GetMapping("/json")
public Map<String, Object> getJsonOutput() {
JSONObject jsonObject = new JSONObject();
//construct jsonObject here
return jsonObject.toMap();
}
you can do this :
#RestController
#RequestMapping("/api")
class MyRestController
{
#GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}").toMap();;
}
}

Spring Android Framework - Retrieving JSON data via HTTP GET

I am using Spring framework to get JSON data from a local server into an Object via Http GET.
But the object is always null(no data stored)
I have double checked the server and it is working fine
the server returns {"Propid":"61", "Proptitle":"3 bhk villa","Propdealer":"admin"}
I have added the Jackson Libraries
I have used StringHttpMessageConverter and it returns the JSON string {"Propid":"61", "Proptitle":"3 bhk villa","Propdealer":"admin"}
Throws exception:Could not extract response: no suitable HttpMessageConverter found for response type [com.aditya.master.classes.Prop] and content type [text/html;charset=UTF-8]
Here is the code that parses the JSON response
URI targetUrl= UriComponentsBuilder.fromUriString("http://192.168.1.9/PinSpace/oauth/")
.path("request_access/")
.queryParam("query", "get_property")
.queryParam("access_token", auth_code)
.queryParam("prop_id", "61")
.build()
.toUri();
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setAccept(Collections.singletonList(new MediaType("application", "json")));
HttpEntity<?> requestEntity = new HttpEntity<Object>(requestHeaders);
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
ResponseEntity<Prop> responseEntity = restTemplate.exchange(targetUrl, HttpMethod.GET, requestEntity, Prop.class);
Prop result = responseEntity.getBody();
Here is the Prop class
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
#JsonIgnoreProperties(ignoreUnknown = true)
public class Prop {
#JsonProperty
private String Propid, Proptitle, Propdealer;
public String getPropid() {
return Propid;
}
public void setPropid(String propid) {
Propid = propid;
}
public String getProptitle() {
return Proptitle;
}
public void setProptitle(String proptitle) {
Proptitle = proptitle;
}
public String getPropdealer() {
return Propdealer;
}
public void setPropdealer(String propdealer) {
Propdealer = propdealer;
}
}
Please suggest a solution
Thanks!
You can test deserialization with follow code:
ObjectMapper objectMapper = new ObjectMapper();
String content = "{\"Propid\":\"61\", \"Proptitle\":\"3 bhk villa\",\"Propdealer\":\"admin\"}";
objectMapper.readValue(content , Prop.class);
This trows exeception
org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "Propid"
which means that fields naming in your class is incorrect or you need to point correct names in #JsonProperty annotation
I suggest you to use next structure:
public class Prop {
private String propid;
private String proptitle;
private String propdealer;
public String getPropid() {
return propid;
}
#JsonProperty("Propid")
public void setPropid(String propid) {
this.propid = propid;
}
public String getProptitle() {
return proptitle;
}
#JsonProperty("Proptitle")
public void setProptitle(String proptitle) {
this.proptitle = proptitle;
}
public String getPropdealer() {
return propdealer;
}
#JsonProperty("Propdealer")
public void setPropdealer(String propdealer) {
this.propdealer = propdealer;
}
}
There is a way to get this to work with an incorrect MIME type as well: you just need to add "text/html" to your list of accepted media types. like so:
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> mediaTypeList = new ArrayList<MediaType>();
//...
mediaTypeList.addAll( jsonConverter.getSupportedMediaTypes() );
mediaTypeList.add(MediaType.TEXT_HTML);
jsonConverter.setSupportedMediaTypes(mediaTypeList);
this will be quite handy if you don't have access to the server.
NOTE
there's probably a less verbose way to do this, but I'm just getting back to Java after 10 years in other environs :-)

Categories

Resources