I am trying to use PATCH method in my client using CXF implementation of JAX-RS. At first I defined the PATCH annotation as
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH {
}
Referencing what was written here : How to have a @PATCH annotation for JAX-RS?
Then I found out @PATCH was added into CXF 3.1.2, so I changed version in my maven's pom.xml and indeed there is public @interface PATCH
inside of package org.apache.cxf.jaxrs.ext;
and the code actually looks exactly as what I posted above.
However, when I try to use this annotation on my service definition as
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface AbcService {
@PATCH
@Path("/abc/efg")
public SomeDTO patchSomething(RequestObject request);
}
I end up with the java.net.ProtocolException: Invalid HTTP method: PATCH
as was said in the queston link I posted above. They discuss some solution for this with Jersey, however what I can I do in CXF, so that I can use :
AbcService abcService = JAXRSClientFactory.create(myURI, AbcService.class, myProviders, true);
abcService.patchSomething(new RequestObject('something'));
So I have couple of questions:
You also have a choice of different transports such as HTTP, JMS, JBI and the choice of front-end API's like JAX-RS and JAX-WS. Having so many options for web service development, there is a need for an open source services framework to glue all the above mentioned options together and that is what Apache CXF does.
In Apache Camel, the Camel CXF component is the key to integrating routes with Web services. You can use the Camel CXF component to create a CXF endpoint, which can be used in either of the following ways: Consumer — (at the start of a route) represents a Web service instance, which integrates with the route.
This tutorial has been prepared to cater the needs of both the beginners and experts in Apache CXF. The tutorial has a flow that takes you from the simpler concepts to in depth ones and lets you gain confidence as you progress through it.
The HelloWorld interface is implemented in the HelloWorldImpl Apache CXF class as shown below − The greetings method receives a parameter of string type, appends it to a greeting message and returns the resultant string to the caller. Next, we write the server application to host the HelloWorld service.
It turns out it's cause because in JAVA7, HttpURLConnection doesn't support PATCH, the supported methods in that class are defined statically as
private static final String[] methods = {
"GET", "POST", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"
};
However it is possible to send PATCH request in CXF, but the Conduit object must be of type AsyncHTTPConduit
.
To make CXF use AsyncHTTPConduit, you can programatically achieve it like this
AbcService service = JAXRSClientFactory.create(myURI, AbcService.class, myProviders, true);
WebClient.getConfig(service).getRequestContext().put("use.async.http.conduit", true);
service.patchEnvironmentParameters(patchRequest);
Or
WebClient client = WebClient.create("http://localhost:53261/v1-0/api/environment/parameters");
WebClient.getConfig(client).getRequestContext().put("use.async.http.conduit", true);
client.invoke("PATCH", "{}");
But beware !! In order to make this work, you have put this dependency into your project
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-hc</artifactId>
<version>${cxf.version}</version>
</dependency>
Also make sure that you use the same version of cxf-rt-transports-http-hc
and cxf
.
But as you can see what I described doesn't solve the original issue, this way I just made 1 specific PATCH request. However in my project there are many PATCH services defined using interfaces like I showed originally
public interface AbcService {
@PATCH
@Path("/abc/efg")
public SomeDTO patchSomething(RequestObject request);
}
So in order to use the AsyncHTTPConduit only on PATCH methods, I had to write custom CXF interceptor, about which you can learn more here http://cxf.apache.org/docs/interceptors.html The interceptor I wrote runs in PRE_LOGIC phase and it checks what kind of method is used and in case it PATCH, it defined the conduit property. Then in latter phases of service invocation, CXF uses this property to choose which Conduit implementation should be used, and so after
if ( message.get(Message.HTTP_REQUEST_METHOD).equals("PATCH") {
message.put("use.async.http.conduit", true);
}
the AsyncHTTPConduit
instance will be used with which the PATCH will work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With