How to work with Patch method in Webclient? - spring-boot

I have been searching a example for patch method in Webclient. I have a four fields in my Model class, I need to update one field (i.e status field), Hence I have decided to use Patch method. But I don't any examples in internet.
I have a piece of code in RestTemplate, here I need it in Webclient, as I'm migrating to Webclient. How to achieve below code?
public void updateProfile(UpdateProfile profile, String uniqueId) {
HttpHeaders headers = new HttpHeaders();
MediaType mediaType = new MediaType("application", "merge-patch+json");
headers.setContentType(mediaType);
HttpEntity<UpdateProfile> entity = new HttpEntity<>(profile, headers);
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
RestTemplate restTemplate = new RestTemplate(requestFactory);
restTemplate.exchange(firebaseUrl+"/"+path+"/" + uniqueId + ".json",
HttpMethod.PATCH, entity, Void.class);
}

You can use the following patch method sample from the web client, i have not tested but i hope so you can use the similar approach.
WebClient webClient = WebClient.create(firebaseUrl);
webClient.patch()
.uri("+path+" + uniqueId + ".json")
.contentType(MediaType.valueOf("application/json-patch+json"))
.bodyValue(data)
.exchange();
remember to add the below artifact in your pom.xml,
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

Related

Sending a multipart request using RestTemplate

I want to make a multipart request to some external API (created using Spring Boot) but all I get is Required request part 'file' is not present.
I know the source code of the external API but I can't modify it. It looks like this:
#PostMapping("/upload")
public ResponseEntity handleFileUpload(#RequestParam("file") MultipartFile file){
return ResponseEntity.ok().build();
}
And from my application I create and send requests exactly like on the following snippet:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body
= new LinkedMultiValueMap<>();
body.add("file", "dupa".getBytes());
HttpEntity<MultiValueMap<String, Object>> requestEntity
= new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate
.postForEntity("http://api:8080/upload", requestEntity, String.class);
return response.getBody();
What's the reason it doesn't work? The above code rewritten using Apache HttpClient works like charm.
You basically have two options, the solution with byte array:
map.add("file", new ByteArrayResource(byteArrayContent) {
#Override
public String getFilename() {
return "yourFilename";
}
});
I remember having a problem with just adding a byte array, so you need to have a filename too and use ByteArrayResource.
Or adding a File:
map.add("file", new FileSystemResource(file));

413 request entity too large issue in HTTP Get method call

Please don't mistake it as already asked question. The main difference here is, this issue is coming in Get method call. All the solutions discussed here or other places talks about either POST method or multipart form data.
Configuration I have provided is as below:
String url = env.getProperty(ApplicationConstants.PMCC_MANAGER_REGION_QUERY_URL);
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParam("inTIS_PMA_NUMBER","ALL");
URI uri = builder.build().toUri();
RestTemplate restTemplate = getRestTemplateBuilder().build();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
private RestTemplateBuilder getRestTemplateBuilder() {
Integer connectionTimeOut = 2000;
Integer readTimeOut = 3000;
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
restTemplateBuilder.setConnectTimeout(connectionTimeOut);
restTemplateBuilder.setReadTimeout(readTimeOut);
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setBufferRequestBody(false);
restTemplateBuilder.requestFactory(factory);
return restTemplateBuilder;
}
This code is part of Spring Boot application and deployed in WebLogic server.

spring boot application periodic post request via resttemplate in json

Below is my spring boot code snippet to post json data to server url every few min to tell that I am alive and running(which loads my json input data to db). purpose of this post request is to update the status on application monitoring tool.
What could be the right approach to implment this behaviour in my spring boot app? Is their any decorator api to do such post request to url, every few miuntes through out the application.? how can I know the time of successful post request to do next post request ? Please help me. Thanks in advance.
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
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);
Why don't you use the #Scheduled annotation? This will seutes.nd your REST request every 3 minutes...
#Component
public class Heartbeater {
#Scheduled(fixedDelay = 180000)
public void heartbeat() {
// Your code is below...
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
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);
}

Uploading jar to nexus with Spring RestTemplate

I would like to use Spring's RestTemplate to upload a jar to nexus. I found instructions on how to do it using curl here, which works just fine. However I have utterly failed in converting this to a RestTemplate call. Here is my code:
String auth = "admin:admin123";
byte[] encodedAuth = Base64.encodeBase64( auth.getBytes(Charset.forName("US-ASCII")) );
String authHeader = "Basic " + new String( encodedAuth );
RestTemplate restTemplate = new RestTemplate();
LinkedMultiValueMap<String, Object> files = new LinkedMultiValueMap<>();
files.add("r", "releases");
files.add("hasPom", "false");
files.add("e", "jar");
files.add("g", "com.test.proj");
files.add("a", "my-artifact");
files.add("v", "1.0.0");
files.add("p", "jar");
files.add("file", new ByteArrayResource(jarBytes));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.set("Authorization", authHeader);
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<>(files, headers);
String response = restTemplate.postForObject("http://localhost:8081/nexus/service/local/artifact/maven/content", entity, String.class);
This fails with a 400 Bad Request. After looking at the source, it looks like my file is failing this key check:
for (FileItem fi : files) {
if (fi.isFormField()) {
// parameters are first in "nibble"
processFormField(request, uploadContext, fi);
}
else {
// a file, this means NO parameters will income anymore
// we either received all the GAVs as params, or we have a POM to work with (file1)
...
FileItem.isFormField is from Apache Commons FileUpload. Does anyone know how I could get this to succeed with my "file" that I am passing in?
In another question (FileUpload isFormField() returning true when submitting file) the answer suggests that I need a name field, or perhaps in my case, the "type" doesn't come through. If this is the case, is it possible to specify these while making a post request?
I'm thinking that this currently isn't possible with RestTemplate. I opted to use Apache's HttpComponents, which has worked wonderfully. Here is the resulting code:
public void uploadToNexus(String version, File myJar, String artifactId)
{
try(CloseableHttpClient httpClient = HttpClients.createDefault())
{
HttpPost httpPost = new HttpPost("http://admin:admin123#mydomain:8081/nexus/service/local/artifact/maven/content");
FileBody jarFileBody = new FileBody(myJar);
HttpEntity requestEntity = MultipartEntityBuilder.create()
.addPart("r", new StringBody("releases", ContentType.TEXT_PLAIN))
.addPart("hasPom", new StringBody("false", ContentType.TEXT_PLAIN))
.addPart("e", new StringBody("jar", ContentType.TEXT_PLAIN))
.addPart("g", new StringBody("com.domain.my", ContentType.TEXT_PLAIN))
.addPart("a", new StringBody("my-artifactId", ContentType.TEXT_PLAIN))
.addPart("v", new StringBody(version, ContentType.TEXT_PLAIN))
.addPart("p", new StringBody("jar", ContentType.TEXT_PLAIN))
.addPart("file", jarFileBody)
.build();
httpPost.setEntity(requestEntity);
try(CloseableHttpResponse response = httpClient.execute(httpPost))
{
logger.info("response from nexus: {}", response.toString());
}
}
catch (IOException e)
{
throw new RuntimeException("Unable to close the httpClient", e);
}
}
I needed the following maven dependencies:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.4.1</version>
</dependency>

Spring Rest Template to send JsonArray

I am using spring rest template to send json array as request. Source code to send request is as follow:
JSONArray jsonArray = new JSONArray();
for (Iterator iterator = itemlist.iterator(); iterator.hasNext();) {
Item item = (Item)iterator.next();
JSONObject formDetailsJson = new JSONObject();
formDetailsJson.put("id", item.getItemConfId());
formDetailsJson.put("name", item.getItems().getItemName());
formDetailsJson.put("price", item.getPrice());
formDetailsJson.put("Cost",item.getCost());
jsonArray.put(formDetailsJson);
}
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// Pass the new person and header
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
System.out.println("Json Object : "+entity);
// Send the request as POST
try {
ResponseEntity<String> result = restTemplate.exchange("my url", HttpMethod.POST, entity, String.class);
} catch (Exception e) {
logger.error(e);
return "Connection not avilable please try again";
}
And to accept request:
#RequestMapping(value = "/testStock", method = RequestMethod.POST,headers="Accept=application/xml, application/json")
public #ResponseBody int testStock(#RequestBody List<ItemList> jsonArray) {
logger.debug("Received request to connect ms access : "+jsonArray.size());
//int returnSizecount = stockList.getStocklst().size();
return 1;
}
The problem is that it giving me following error:
Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONArray].Any suggestion is greatly acceptable.
There are no MessageConverter for JSONArray, so I suggest do the following.
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
Convert Class JSONArray to String, and add that to HttpEntity, you know use toString
java.lang.String toString()
Make a JSON text of this JSONArray.
HttpEntity entity = new HttpEntity(jsonArray.toString(), headers);
Or change to Jackson implementation Spring have support to that. XD
If you dont want to do the above, consider create your own implementation of messageConverter, that will work but is harder
update
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
headers.setContentType(MediaType.APPLICATION_JSON);
update 2 Change endpoint to.
#RequestMapping(value = "/testStock", method = RequestMethod.POST)
public #ResponseBody int testStock(#RequestBody String jsonArray) {
you need to have httpmessageconverter configured for your resttemplate, please read my post for configuring http message conveter for you webservice
http://stackoverflow.com/questions/19963127/new-to-spring-and-jackson-2-what-does-this-bean-declaration-allow-for-in-a-spri/19973636#19973636.
and for you problem to convert your http request to json you might add this entry in your restemplate configuration
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
The error is quite straightforward. You do not have a converter for the JSONArray. Converting the array to a String (using toString) did help you here, but there is a better way:
Just add a converter for the json.org objects:
Add this to your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
</dependency>
And then on your ObjectMapper add the JsonOrgModule:
mapper.registerModule(new JsonOrgModule());

Resources