Java: Request body in XML or JSON without using String - java

I am developing an application using Spring Boot (with Java).
This application has to call several external services and each of these services requires a complicated body (in json or xml) (this input can vary! The fields I pass to it are not required so sometimes I might even pass a subset of these fields). These are examples of inputs that services can receive:
{
"field1": "string",
"field2": "string",
"field3": "string",
"field4": 0,
}
<input>
<input1>my_string</input1>
<input2>my_string</input2>
</input>
I use RestTemplate to make HTTP calls. This is an example. I use a Java String to model the HTTP body (but it has the big defect that it is not editable but hard-coded!):
String Jsonbody = "{\r\n"
+ " \"field1\": \""+myString1+"\"\r\n"
+ " \"field2\": \""+myString2+"\"\r\n"
+ "}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<String>(Jsonbody, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MyResponseClass> response = restTemplate.postForEntity(url, request, MyResponseClass.class);
It is very bad to have a body hard-coded like this in the JsonBody variable. What is the way to have an object in which I dynamically insert strings and which automatically creates a JSON object (which I can then convert to a string to put in the .postForEntity method)? The same issue for XML input types.

There are multiple libraries as Gson or Jackson that actually allow you to work with JSON as they are Java Objects to finally serialize them as a body.
If you want to give it a try, you would just need to include Gson as dependency:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
Then you'd have to create a POJO for your POST body:
public class JsonBody {
private List<String> fields = new LinkedList<>();
void addField(String field) {
fields.add(field);
}
}
And feel free to add as many String as you want that it will be parsed afterwards.
JsonBody jsonBody = new JsonBody();
Gson gson = new Gson();
jsonBody.addField(myString1);
jsonBody.addField(myString2);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> request = new HttpEntity<String>(gson.toJson(jsonBody), headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<MyResponseClass> response = restTemplate.postForEntity(url, request, MyResponseClass.class);
This would set your JSON to:
{
fields: [
contentMyString1,
contentMyString2
]
}
Taking the previous example into account, you can just modify and format your JSON as you want in the form of a POJO and use the Gson::toJson(String) function from Gson.
Of course if you just create a POJO as:
public class JsonBody {
private String field1;
private String field2;
private String field3;
private Integer field4;
}
Then the output would be the same one than you have in your initial example.

Use the ObjectMapper class like this ...
ObjectMapper objectMapper = new ObjectMapper();
Car car = new Car("yellow", "renault");
objectMapper.writeValue(new File("target/car.json"), car);
The output will be
{"color":"yellow","type":"renault"}
Here's some more data on the topic https://www.baeldung.com/jackson-object-mapper-tutorial
Same approach is used for mapping objects into XML (https://www.baeldung.com/jackson-xml-serialization-and-deserialization)

Related

How to I send a Rest Template Request Body with multiple objects in it

I have to send a request body like this
{
"request": {
"header": {
"correlationId": "Test",
"appId": "12345"
},
"payload": {
"leadId": "12345",
"applicationNo": "",
"proposalNo": "P123",
"policyNo": "100",
"issuanceDt": "01-06-2022",
"docName": "ABCD.pdf",
"docType": "Proposal Form"
}
}
}
I also have headers "username" and "password".
I have created Models for request, header and payload with respective fields.
How do I send this using rest template?
Create a new HttpEntity, populate it with headers and body and exchange, using RestTemplate like this. Payload - is a class containing your payload, and I assumed you have a builder (you can use just a map, indeed)
final HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.add("correlationId", "value");
httpHeaders.add("appId", "value");
HttpEntity<Payload> httpEntity = new HttpEntity<>(Payload.builder()
//bulider population goes here
.build(),httpHeaders);
final RestTemplate restTemplate = new RestTemplate();
restTemplate.exchange(uri, HttpMethod.POST,httpEntity);
For Header, you just need to add parameters in the headers of HTTP request, Payload is what you are looking for, You can define a DTO class having the same JSON structure which will then be automatically deserialized and mapped to your DTO class.
public class Payload{
public String leadId;
public String applicationNo;
public String proposalNo;
public String policyNo;
public String issuanceDt;
public String docName;
public String docType;
}

Can I get a ResponseEntity (Spring) parametrized with a type either parametrized?

I'm using RestTemplate and SpringBoot 2.0.
I have this class which represents a custom JSON response to rest calls.
MyCustomResponse<T> {
private T content;
public T getContent() {
return content;
}
}
The code snippet below is a example of use:
String LOCALHOST = "http://localhost:8900";
final HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ACCEPT, "application/json");
String url = String.format("%s/ticket/%s", LOCALHOST, protocol);
final HttpEntity<Ticket> request = new HttpEntity<>(headers);
This works fine:
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, RespostaPadrao.class);
But it's not what I need, because getContent returns a object that looks like:
Map< Map < String, Map < String, Map < String, Map < String, Integer >>>>>
and because I want to test a Ticket object instead.
In this line, can I use reflection to parametrize the response or this is impossible?
ResponseEntity<MyCustomResponse> response =
testRestTemplate.getForEntity(url, MyCustomResponse.class);
I know how to fix it with ResponseEntity<String> and parse the JSON to my Ticket. But what I really need is know if is possible delegate this task to RestTemplate or not.
Thanks!

GSON could not convert generic <T> attribute

i currently use Google's GSON library to serialize/deserialize rest service responses.
But i have a little problem. My response object has T response attribute.
public class IninalResponse<T> {
private int httpCode;
private String description;
private T response;
private HashMap<String,String> validationErrors;
...
}
I would like to get response attribute according to object type which i specified. At this example i specified with GetAccessTokenResponse to deserialize T response attribute in the piece of code below.
public IninalResponse getAccessToken(String apikey) {
String path = "https://sandbox-api.ininal.com/v2/oauth/accesstoken";
return doPostIninal(apikey,path,null,GetAccessTokenResponse.class);
}
GSON library successfully deserializes IninalResponse object except for T response field. Gson deserializes it as LinkedTreeMap typed object.
public <T,V> IninalResponse doPostIninal(String apikey, String path,V requestBody, T response) {
RestTemplate template = restClient.getRestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.AUTHORIZATION,apikey);
headers.add(HttpHeaders.DATE, "");
headers.add(HttpHeaders.CONTENT_TYPE, "application/json");
HttpEntity<?> request = new HttpEntity<Object>(requestBody,headers);
ResponseEntity<String> accessTokenResponse = restClient.getRestTemplate().postForEntity(path,request,String.class);
IninalResponse<T> responseBody = new IninalResponse<T>();
responseBody = new Gson().fromJson(accessTokenResponse.getBody(),responseBody.getClass());
System.out.println(accessTokenResponse);
return responseBody;
}
Still i have no idea why gson could not deserialize ? What exactly am i missing ?
Due to Java's type erasure, you need to make a trick to serialize/deserialize generic types:
Type fooType = new TypeToken<IninalResponse<TheType>>() {}.getType();
gson.fromJson(accessTokenResponse.getBody(), fooType);
where TheType is the type you passed in during serialization (String I suppose).
Serialization goes as this:
Type fooType = new TypeToken<IninalResponse<String>>() {}.getType(); // I assume it was a String here.
gson.toJson(someString, fooType);

Spring restTemplate get raw json string

How can I get the raw json string from spring rest template? I have tried following code but it returns me json without quotes which causes other issues, how can i get the json as is.
ResponseEntity<Object> response = restTemplate.getForEntity(url, Object.class);
String json = response.getBody().toString();
You don't even need ResponseEntitys! Just use getForObject with a String.class like:
final RestTemplate restTemplate = new RestTemplate();
final String response = restTemplate.getForObject("https://httpbin.org/ip", String.class);
System.out.println(response);
It will print something like:
{
"origin": "1.2.3.4"
}

Java POST application/json [duplicate]

I didn't find any example how to solve my problem, so I want to ask you for help. I can't simply send POST request using RestTemplate object in JSON
Every time I get:
org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type
I use RestTemplate in this way:
...
restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> list = new ArrayList<HttpMessageConverter<?>>();
list.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(list);
...
Payment payment= new Payment("Aa4bhs");
Payment res = restTemplate.postForObject("http://localhost:8080/aurest/rest/payment", payment, Payment.class);
What is my fault?
This technique worked for me:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.put(url, entity);
I ran across this problem when attempting to debug a REST endpoint. Here is a basic example using Spring's RestTemplate class to make a POST request that I used. It took me quite a bit of a long time to piece together code from different places to get a working version.
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"queriedQuestion\":\"Is there pain in your hand?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
The particular JSON parser my rest endpoint was using needed double quotes around field names so that's why I've escaped the double quotes in my requestJson String.
I've been using rest template with JSONObjects as follow:
// create request body
JSONObject request = new JSONObject();
request.put("username", name);
request.put("password", password);
// set headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(request.toString(), headers);
// send request and parse result
ResponseEntity<String> loginResponse = restTemplate
.exchange(urlString, HttpMethod.POST, entity, String.class);
if (loginResponse.getStatusCode() == HttpStatus.OK) {
JSONObject userJson = new JSONObject(loginResponse.getBody());
} else if (loginResponse.getStatusCode() == HttpStatus.UNAUTHORIZED) {
// nono... bad credentials
}
As specified here I guess you need to add a messageConverter for MappingJacksonHttpMessageConverter
I'm doing in this way and it works .
HttpHeaders headers = createHttpHeaders(map);
public HttpHeaders createHttpHeaders(Map<String, String> map)
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
for (Entry<String, String> entry : map.entrySet()) {
headers.add(entry.getKey(),entry.getValue());
}
return headers;
}
// Pass headers here
String requestJson = "{ // Construct your JSON here }";
logger.info("Request JSON ="+requestJson);
HttpEntity<String> entity = new HttpEntity<String>(requestJson, headers);
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
logger.info("Result - status ("+ response.getStatusCode() + ") has body: " + response.hasBody());
logger.info("Response ="+response.getBody());
Hope this helps
If you are using Spring 3.0, an easy way to avoid the org.springframework.web.client.HttpClientErrorException: 415 Unsupported Media Type exception, is to include the jackson jar files in your classpath, and use mvc:annotation-driven config element. As specified here.
I was pulling my hair out trying to figure out why the mvc-ajax app worked without any special config for the MappingJacksonHttpMessageConverter. If you read the article I linked above closely:
Underneath the covers, Spring MVC
delegates to a HttpMessageConverter to
perform the serialization. In this
case, Spring MVC invokes a
MappingJacksonHttpMessageConverter
built on the Jackson JSON processor.
This implementation is enabled
automatically when you use the
mvc:annotation-driven configuration
element with Jackson present in your
classpath.
The "415 Unsupported Media Type" error is telling you that the server will not accept your POST request. Your request is absolutely fine, it's the server that's mis-configured.
MappingJacksonHttpMessageConverter will automatically set the request content-type header to application/json, and my guess is that your server is rejecting that. You haven't told us anything about your server setup, though, so I can't really advise you on that.
Why work harder than you have to? postForEntity accepts a simple Map object as input. The following works fine for me while writing tests for a given REST endpoint in Spring. I believe it's the simplest possible way of making a JSON POST request in Spring:
#Test
public void shouldLoginSuccessfully() {
// 'restTemplate' below has been #Autowired prior to this
Map map = new HashMap<String, String>();
map.put("username", "bob123");
map.put("password", "myP#ssw0rd");
ResponseEntity<Void> resp = restTemplate.postForEntity(
"http://localhost:8000/login",
map,
Void.class);
assertThat(resp.getStatusCode()).isEqualTo(HttpStatus.OK);
}
I was getting this problem and I'm using Spring's RestTemplate on the client and Spring Web on the server. Both APIs have very poor error reporting, making them extremely difficult to develop with.
After many hours of trying all sorts of experiments I figured out that the issue was being caused by passing in a null reference for the POST body instead of the expected List. I presume that RestTemplate cannot determine the content-type from a null object, but doesn't complain about it. After adding the correct headers, I started getting a different server-side exception in Spring before entering my service method.
The fix was to pass in an empty List from the client instead of null. No headers are required since the default content-type is used for non-null objects.
This code is working for me;
RestTemplate restTemplate = new RestTemplate();
Payment payment = new Payment("Aa4bhs");
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("payment", payment);
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<MultiValueMap<String, Object>>(map, headerObject);
Payment res = restTemplate.postForObject(url, httpEntity, Payment.class);
If you dont want to process response
private RestTemplate restTemplate = new RestTemplate();
restTemplate.postForObject(serviceURL, request, Void.class);
If you need response to process
String result = restTemplate.postForObject(url, entity, String.class);
I tried as following in spring boot:
ParameterizedTypeReference<Map<String, Object>> typeRef = new ParameterizedTypeReference<Map<String, Object>>() {};
public Map<String, Object> processResponse(String urlendpoint)
{
try{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
//reqobj
JSONObject request = new JSONObject();
request.put("username", name);
//Or Hashmap
Map<String, Object> reqbody = new HashMap<>();
reqbody.put("username",username);
Gson gson = new Gson();//mvn plugin to convert map to String
HttpEntity<String> entity = new HttpEntity<>( gson.toJson(reqbody), headers);
ResponseEntity<Map<String, Object>> response = resttemplate.exchange(urlendpoint, HttpMethod.POST, entity, typeRef);//example of post req with json as request payload
if(Integer.parseInt(response.getStatusCode().toString()) == HttpURLConnection.HTTP_OK)
{
Map<String, Object> responsedetails = response.getBody();
System.out.println(responsedetails);//whole json response as map object
return responsedetails;
}
} catch (Exception e) {
// TODO: handle exception
System.err.println(e);
}
return null;
}
For me error occurred with this setup:
AndroidAnnotations
Spring Android RestTemplate Module
and ...
GsonHttpMessageConverter
Android annotations has some problems with this converted to generate POST request without parameter. Simply parameter new Object() solved it for me.
If you don't want to map the JSON by yourself, you can do it as follows:
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter()));
ResponseEntity<String> result = restTemplate.postForEntity(uri, yourObject, String.class);
You can make request as a JSON object
JSONObject request = new JSONObject();
request.put("name","abc");
ResponseEntity<JSONObject> response =restTemplate.postForEntity(append_url,request,JSONObject.class); `enter code here`

Categories