Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RestTemplate PATCH request

I have the following definition for PersonDTO:

public class PersonDTO {     private String id     private String firstName;     private String lastName;     private String maritalStatus; } 

Here is a sample record :

{     "id": 1,     "firstName": "John",     "lastName": "Doe",     "maritalStatus": "married" } 

Now, John Doe gets divorced. So I need to send a PATCH request to this URL:

http://localhost:8080/people/1 

With the following request body:

{     "maritalStatus": "divorced" } 

I cannot figure out how to do it. Here is what I tried so far:

// Create Person PersonDTO person = new PersonDTO(); person.setMaritalStatus("Divorced");  // Create HttpEntity final HttpEntity<ObjectNode> requestEntity = new HttpEntity<>(person);  // Create URL (for eg: localhost:8080/people/1) final URI url = buildUri(id);  ResponseEntity<Void> responseEntity = restTemplate.exchange(url, HttpMethod.PATCH, requestEntity, Void.class); 

Here are the problems with the above:

1) As I am setting only MaritalStatus, the other fields would all be null. So if I print out the request, it will look like this:

{     "id": null,     "firstName": "null",     "lastName": "null",     "maritalStatus": "married" // I only need to update this field. } 

Does that mean that I have to a GET before I do a PATCH?

2) I am getting the following stack trace:

08:48:52.717 ERROR c.n.d.t.s.PersonServiceImpl - Unexpected Exception  :  org.springframework.web.client.ResourceAccessException: I/O error on PATCH request for "http://localhost:8080/people/1":Invalid HTTP method: PATCH; nested exception is java.net.ProtocolException: Invalid HTTP method: PATCH     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:580) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:545) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:466) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at com.sp.restclientexample..service.PersonServiceImpl.doPatch(PersonServiceImpl.java:75) ~[classes/:na]     at com.sp.restclientexample..service.PatchTitle.itDoPatch(PatchTitle.java:53) [test-classes/:na]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_20]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_20]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_20]     at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_20]     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) [junit-4.12.jar:4.12]     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) [junit-4.12.jar:4.12]     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) [junit-4.12.jar:4.12]     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) [junit-4.12.jar:4.12]     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.junit.runners.ParentRunner.run(ParentRunner.java:363) [junit-4.12.jar:4.12]     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) [spring-test-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) [.cp/:na]     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) [.cp/:na] Caused by: java.net.ProtocolException: Invalid HTTP method: PATCH     at java.net.HttpURLConnection.setRequestMethod(HttpURLConnection.java:440) ~[na:1.8.0_20]     at sun.net.www.protocol.http.HttpURLConnection.setRequestMethod(HttpURLConnection.java:517) ~[na:1.8.0_20]     at org.springframework.http.client.SimpleClientHttpRequestFactory.prepareConnection(SimpleClientHttpRequestFactory.java:209) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.http.client.SimpleClientHttpRequestFactory.createRequest(SimpleClientHttpRequestFactory.java:138) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.http.client.support.HttpAccessor.createRequest(HttpAccessor.java:76) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:565) ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]     ... 33 common frames omitted 

Appreciate any pointers from folks who have written client applications to consume a Restful webservice using Spring's RestTemplate.

For completeness, let me also state that we use SpringDataRest for our backend restful webservices.

SGB

like image 412
SGB Avatar asked Apr 04 '15 14:04

SGB


People also ask

How do I call a PATCH method in Java?

The PATCH request method is used to modify a resource on the server partially. To send a PATCH request to the server, you need to use the HTTP PATCH method and include the request data in the body of the HTTP message. The Content-Type request header must indicate the data type in the body.

What is PATCH method in API?

In computing, the PATCH method is a request method in HTTP for making partial changes to an existing resource. The PATCH method provides an entity containing a list of changes to be applied to the resource requested using the HTTP Uniform Resource Identifier (URI).

How do you use RestTemplate exchange method?

Rest Template is used to create applications that consume RESTful Web Services. You can use the exchange() method to consume the web services for all HTTP methods. The code given below shows how to create Bean for Rest Template to auto wiring the Rest Template object.

What is RestTemplate getForObject?

The getForObject method fetches the data for the given response type from the given URI or URL template using HTTP GET method. To fetch data for the given key properties from URL template we can pass Object Varargs and Map to getForObject method. The getForObject returns directly the object of given response type.


2 Answers

I solved this problem just adding a new HttpRequestFactory to my restTemplate instance. Like this

RestTemplate restTemplate = new RestTemplate();  HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setConnectTimeout(TIMEOUT); requestFactory.setReadTimeout(TIMEOUT);  restTemplate.setRequestFactory(requestFactory); 

For TestRestTemplate, add

@Autowired private TestRestTemplate restTemplate;  @Before public void setup() {     restTemplate.getRestTemplate().setRequestFactory(new HttpComponentsClientHttpRequestFactory()); } 

PS: You will need add httpClient component in your project

<dependency>     <groupId>org.apache.httpcomponents</groupId>     <artifactId>httpclient</artifactId>     <version>4.4.1</version> </dependency> 
like image 73
Tulio Gomez Rodrigues Avatar answered Sep 16 '22 23:09

Tulio Gomez Rodrigues


For cases where RestTemplate is built from a RestTemplateBuilder, constructor for the custom RestClient can be written as,

public PersonRestClient(RestTemplateBuilder restTemplateBuilder) {   this.restTemplate = restTemplateBuilder.requestFactory(new HttpComponentsClientHttpRequestFactory()).build(); } 

Also, the org.apache.httpcomponents.httpclient dependency needs to added to pom.

like image 40
sompnd Avatar answered Sep 17 '22 23:09

sompnd