Spring mapping JSON to java POJO - java

I have API which returns JSON in this format:
[
{ "shrtName": "abc", "validFrom": "2016-10-23", "name": "aaa", "version": 1 },
{ "shrtName": "def", "validFrom": "2016-11-20", "name": "bbb", "version": 1 },
{ "shrtName": "ghi", "validFrom": "2016-11-22", "name": "ccc", "version": 1 }
]
I have this code which reads API and returns it as a String. But I want to read this API and map it into the Java POJO class.
public String downloadAPI(){
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("API-Key", "4444444-3333-2222-1111-88888888");
HttpEntity<?> requestEntity = new HttpEntity<Object>(headers);
String URL = "https://aaaaaaa.io/api/v1/aaaaaaaaa?date=2015-04-04;
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
ResponseEntity<String> response = restTemplate.exchange(URL, HttpMethod.GET, requestEntity, String.class);
return response.getBody();
}
My questions:
1) Format of POJO?
2) Changes in my method (return type POJO instead of String)

Your JSON is an array that's why []
Create POJO
public class MyPOJO {
private String shrtName;
private Date validFrom;
private String name;
private int version;
}
Remove message converter and refactor restTemplate exchange method to
ResponseEntity<MyPOJO[].class> response = restTemplate.exchange(URL, HttpMethod.GET, requestEntity, MyPOJO[].class);
This is generic function that I use for GET requests
public <T> T getRequestAndCheckStatus(final String url, final Class<T> returnTypeClass,
final List<MediaType> mediaTypes,
final Map<String, String> headerParams,
final Map<String, Object> queryParams) throws Exception {
final HttpHeaders headers = new HttpHeaders();
headers.setAccept(mediaTypes);
setHeaderParamsIfExists(headers, headerParams);
final HttpEntity<String> requestEntity = new HttpEntity<>(headers);
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url);
setQueryParamsIfExists(uriBuilder, queryParams);
final ResponseEntity<T> entity = restTemplate
.exchange(getUrl(uriBuilder),
HttpMethod.GET,
requestEntity,
returnTypeClass);
Assert.assertEquals(HttpStatus.OK, entity.getStatusCode());
return entity.getBody();
}
private void setHeaderParamsIfExists(HttpHeaders headers, Map<String, String> headerParams) {
if(headerParams != null && !headerParams.isEmpty())
headerParams.entrySet()
.forEach(entry -> headers.set(entry.getKey(), entry.getValue()));
}
private void setQueryParamsIfExists(UriComponentsBuilder uriBuilder, Map<String, Object> queryParams) {
if(queryParams != null && !queryParams.isEmpty())
queryParams.entrySet()
.forEach(entry -> uriBuilder.queryParam(entry.getKey(), entry.getValue()));
}
private URI getUrl(UriComponentsBuilder uriBuilder) {
return uriBuilder.build().encode().toUri();
}
In your case you would call it by
getRequestAndCheckStatus("https://aaaaaaa.io/api/v1/aaaaaaaaa", MyPOJO[].class,
Collections.singletonList(MediaType.APPLICATION_JSON_UTF8),
new HashMap<String, String>(){{ put("API-Key", "4444444-3333-2222-1111-88888888"); }}),
new HashMap<String, Object>(){{ put("Date", "2015-04-04"); }});
Additionaly, for Date I recommend to use long and then in controller parse it to Date. I see that you use https protocol, have you configured certificate ?

Create a pojo with those atrributes and use jackson for convert from json String to your pojo.
public class MapClass {
private String shrtName;
private Date validFrom;
private String name;
private int version;
}

Related

Consume a restful service with authentication

Today I'm dealing with an issue creating a client to consume a restful service with a Bearer JWT. After appying the swagger codegen maven plugin I got the following GET operation what I need to consume in my new service:
public String getRelationByCucoIdUsingGET(Integer cucoId, String GS_AUTH_TOKEN) throws RestClientException {
Object postBody = null;
// verify the required parameter 'cucoId' is set
if (cucoId == null) {
throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, "Missing the required parameter 'cucoId' when calling getRelationByCucoIdUsingGET");
}
// create path and map variables
final Map<String, Object> uriVariables = new HashMap<String, Object>();
uriVariables.put("cucoId", cucoId);
String path = UriComponentsBuilder.fromPath("/getRelationByCucoId/{cucoId}").buildAndExpand(uriVariables).toUriString();
final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<String, String>();
final HttpHeaders headerParams = new HttpHeaders();
final MultiValueMap<String, Object> formParams = new LinkedMultiValueMap<String, Object>();
if (GS_AUTH_TOKEN != null)
headerParams.add("GS-AUTH-TOKEN", apiClient.parameterToString(GS_AUTH_TOKEN));
final String[] accepts = {
"application/json"
};
final List<MediaType> accept = apiClient.selectHeaderAccept(accepts);
final String[] contentTypes = { };
final MediaType contentType = apiClient.selectHeaderContentType(contentTypes);
String[] authNames = new String[] { };
ParameterizedTypeReference<String> returnType = new ParameterizedTypeReference<String>() {};
return apiClient.invokeAPI(path, HttpMethod.GET, queryParams, postBody, headerParams, formParams, accept, contentType, authNames, returnType);
}
The model class is as follow:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#JsonIgnoreProperties(ignoreUnknown = true)
public class CuCoPerson {
private Integer cucoId;
private List<CustomerRelation> customers;
}
And last, I have done this service but it doesnt work and I don't know how to create the controller to use this service.
#Service
public class CustomerRelationService {
RestControllerApi restControllerApi = new RestControllerApi();
public void getCustomers(Integer cudoId, Principal auth) {
restControllerApi.getRelationByCucoIdUsingGET(cudoId, auth.getName());
}

How can I associate JSON object of the api response to java classes when having the intermediate json "data" attribute?

Thank you for clicking here.
I have an JSON REST API (providing by Directus CMS). All API responses contains a json object with a "data" attribute containing what I want.
{
"data": {
"id": 1,
"status": "published",
"sort": null,
"user_created": "5a91c184-908d-465e-a7d5-4b648029bbe0",
"date_created": "2022-04-26T09:43:37.000Z",
"user_updated": "5a91c184-908d-465e-a7d5-4b648029bbe0",
"date_updated": "2022-05-30T14:23:50.000Z",
"Titre": "Réseaux Sociaux",
"Description": "Retrouvez les dernières news en direct sur nos réseaux sociaux!",
"Lien": "https://www.instagram.com/univlorraine/",
"ImageArrierePlan": "f23ffd53-7244-4439-a8cf-41bd0fd3aa72",
"Erreur_Bloc": null
}
}
This data attribute can be a object or a list of objects depending the request.
I have a Java Spring application with a service consuming the API. I'm using RestTemplate with exchange method.
public Object callAPI(String url, HttpMethod httpMethod, Object body, MultiValueMap<String, String> headers, Class<?> classe) {
final RestTemplate rt = new RestTemplate();
try {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
rt.setRequestFactory(requestFactory);
final HttpEntity<?> request = new HttpEntity<>(body, headers);
final ResponseEntity<?> response = rt.exchange(url, httpMethod, request, classe);
if (response.getStatusCode().equals(HttpStatus.OK)) {
return response.getBody();
}
else return response.getStatusCode();
} catch (final Exception e) {
System.out.println(e);
return null;
}
}
In the exchange method I pass an existing class to directly link response data with the provided class.
The probleme is that I have this data attribute which prevents me from linking the data.
Does anyone have a solution to this probleme please?
----UPDATE----
Thanks to the response of AlbiKai, I created a generic Wrapper class :
public class Wrapper<T> {
private T data;
public void set(T data) {
this.data = data;
}
public T get() {
return data;
}
}
I then tried to put this Wrapper in the exchange :
public <classe> Object callAPI(String url, HttpMethod httpMethod, Object body, MultiValueMap<String, String> headers, Class<?> classe) {
final RestTemplate rt = new RestTemplate();
try {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
rt.setRequestFactory(requestFactory);
final HttpEntity<?> request = new HttpEntity<>(body, headers);
final ResponseEntity<?> response = rt.exchange(url, httpMethod, request, Wrapper<classe>.class);
But I get the error "Cannot select from parameterized type" on the Wrapper :/
You can create a wrapper class that match the json response : an object with only one attribute named "data" type of desire final class (or a list) and use it in the exchange method.
public class wrapper {
YourClass data;
}
I gave up with the Wrapper etc...
I just pass a String class and work with it in my controllers to delete this "data" property and map the string with a class.
Service :
public String callAPI(String url, HttpMethod httpMethod, Object body, MultiValueMap<String, String> headers) {
final RestTemplate rt = new RestTemplate();
try {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
rt.setRequestFactory(requestFactory);
final HttpEntity<?> request = new HttpEntity<>(body, headers);
final ResponseEntity<String> response = rt.exchange(url, httpMethod, request, String.class);
if (response.getStatusCode().equals(HttpStatus.OK)) {
return response.getBody();
}
else return response.getStatusCode().toString();
} catch (final Exception e) {
System.out.println(e);
return null;
}
}
One controller :
public List<BlocInformation> getBlocInformation() {
String url = "http://localhost:8055/items/bloc_information/?fields=*,Erreur_Bloc.*";
final RestAPIService blocService = new RestAPIService();
String response = blocService.callAPI(url, HttpMethod.GET, null, null);
if (response != null) {
String result = response.substring(8, response.length() - 1);
ObjectMapper mapper = new ObjectMapper();
List<BlocInformation> blocInformationList = null;
try {
blocInformationList = Arrays.asList(mapper.readValue(result, BlocInformation[].class));
} catch (IOException e) {
e.printStackTrace();
}
return blocInformationList;
}
return null;
}

How to Get particular value from restTemplate in springboot?

I have an api with given request body and response , now I have to call restTemplate for it and get particular response from it
This is my requestBody ->
{"ids":["MS8B50FHS"]}
And this is my response ->
{
"status": 200,
"success": true,
"message": "detail found!",
"data": {
"MS8B50FHS": {
"ids": "MS8B50FHS",
"creditTerm": "Credit 45 days"
}
}
}
Now for this I need to get creditterm by calling a restTemplate
#Override
public String findByUniqueSupplierId (String ids){
final String url = BaseUrl ;
HttpHeaders headers = new HttpHeaders();
HttpEntity<Object> requestEntity = new HttpEntity<>(headers);
Map<String, List<String>> params = new HashMap<>();
params.put("ids", Collections.singletonList(ids));
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> object = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class , params);
return object.getBody();
}
I was trying something like this but not getting result
You can assign JSON data to objects using the fromJson() method from the Gson library.
String body = object.getBody();
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(body, HashMap.class);
Map<String, Object> data = (Map<String, Object>) map.get("data");
Map<String, Object> creditTerm = (Map<String, Object>) data.get("MS8B50FHS");
String creditTermValue = creditTerm.get("creditTerm").toString();
System.out.println(creditTermValue);
Could be refactored.

Post Json Array in Json Object via RestTemplate in Spring Boot

Im trying to post an array in a json object using RestTemplate
{
"update": {
"name": "xyz",
"id": "C2",
"Description": "aaaaaa",
"members": ["abc", "xyz"]
}
}
Here is my PostMapping Controller
#PostMapping(value = "/update")
public Update update(#RequestBody Update update) {
String url = "";
HttpHeaders headers = createHttpHeaders("username", "passowrd");
JSONObject jsonObject = new JSONObject();
jsonObject.put("update", update);
HttpEntity<JSONObject> request = new HttpEntity<>(jsonObject, headers);
ResponseEntity<Update> update = restTemplate.exchange(url, HttpMethod.POST,request, Update.class);
return update.getBody();
}
And this my POJO
public class Update {
private String name;
private String id;
private String Descripion;
private List<String> members;
}
And Im getting 500
{
"timestamp": "2020-03-13T06:31:21.822+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No HttpMessageConverter for org.json.JSONObject and content type \"application/json\""
}
Try to configure your RestTemplate with a Json Message Converter.
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
You may refer this blog post for a detailed explanation
https://www.baeldung.com/spring-httpmessageconverter-rest
And then perform your rest call as below.You will no longer need to explicitly create a Json Object.
String url = "";
HttpEntity<Update> request = new HttpEntity<>(update, headers);
ResponseEntity<Update> firewallGroupUpdate = restTemplate.exchange(url, HttpMethod.POST, request, Update.class);
return firewallGroupUpdate.getBody();
Changed resttemplate.exchange to resttemplate.postForObject.
And also changed the method to return String.
public String groupUpdate(#RequestBody String groupUpdate) {
String url = "";
HttpHeaders headers = createHeaders("username","password");
headers.setContentType(MediaType.APPLICATION_JSON);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
HttpEntity<String> requestEntity = new HttpEntity<String>(groupUpdate, headers);
String response = restTemplate.postForObject(url,requestEntity,String.class);
return response;
}

spring-boot-starter-web enum and deserialize fail

I want deserialize a Object but json data is a string and the element of my object is not a string but a enum (of string).
My Object (want deserialize):
public enum ResponseStatus {
SUCCESS, ERROR, WARNING, NO_ACCESS
}
public class SessionResponse extends OperationResponse {
#ApiModelProperty(required = true, value = "")
private SessionItem item;
public SessionResponse() {
super();
}
public SessionItem getItem() {
return item;
}
public void setItem(SessionItem item) {
this.item = item;
}
}
public class OperationResponse {
#ApiModelProperty(required = true)
private ResponseStatus operationStatus;
private String operationMessage;
public ResponseStatus getOperationStatus() {
return operationStatus;
}
public void setOperationStatus(ResponseStatus operationStatus) {
this.operationStatus = operationStatus;
}
public String getOperationMessage() {
return operationMessage;
}
public void setOperationMessage(String operationMessage) {
this.operationMessage = operationMessage;
}
}
I use this web client:
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-Type", "application/json");
HttpEntity<Login> request = new HttpEntity<>(new Login("demo", "demo"), headers);
ResponseEntity<String> response = new TestRestTemplate().postForEntity("http://localhost:" + port + "/session", request, String.class);
System.out.println(response.getBody());
console:
{
"operationStatus" : "SUCCESS",
"operationMessage" : "Login Success",
"item" : {
"token" : "eyJhbGciOiJIUzI",
"userId" : "demo",
"firstName" : "Zinédine",
"lastName" : "Zidane",
"email" : "zzidane#mail.com",
"roles" : [ ]
}
}
But if I use
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Content-Type", "application/json");
HttpEntity<Login> request = new HttpEntity<>(new Login("demo", "demo"), headers);
ResponseEntity<SessionResponse> response = new TestRestTemplate().postForEntity("http://localhost:" + port + "/session", request, SessionResponse.class);
System.out.println(response.getBody());
trace:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class com.xxx.xxx.model.session.SessionResponse]
EDIT 1
if I add gson deserializer just after, is it OK
Gson gson = new Gson();
SessionResponse s = gson.fromJson(response.getBody(), SessionResponse.class);
System.out.println(s.getItem().getLastName());
is it possoble to use gson directly in TestRestTemplate().postForEntity ?

Categories