JAX-RSPage edited by Sergey BeryozkinChanges (2)
Full Content
JAX-RS (JSR-311)
IntroductionCXF supports JAX-RS (JSR-311), Java API for RESTful Web Services. JAX-RS standardizes the way RESTful services can be developed in Java. CXF 2.3.0 supports JSR-311 API 1.1. CXF 2.1.x supports JSR-311 API 0.8. JAX-RS related demos are located under the samples/jax_rs directory. MigrationMigrating from JAX-RS 0.8 to 1.0The following major changes in 1.0 will most likely affect users migrating from 0.8
Migrating from 1.0 to 1.1Existing JAX-RS 1.0 applications should run in CXF 2.3.0 without any problems.
Maven dependenciesTo incorporate JAX-RS, you will need: <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxrs</artifactId> <version>2.3.0</version> </dependency>
For CXF 2.2.x the dependencies are similar :
If Spring configuration is used then add spring.jar from the Spring distribution or the spring jars available in the CXF distribution. When creating client proxies from concrete classes the cglib-nodep-2.1_3.jar needs to be added. You do not need to add JAXB libraries if you do not use JAXB. If you depend on Jetty then you will also need to add Jetty 7 or Jetty 6 jars shipped with CXF 2.3.0 and 2.2.12 respectively. We will work on reducing the set of required dependencies. CXF JAX-RS bundleA standalone JAX-RS bundle is now available which may be of interest to users doing JAX-RS work only. Understanding the BasicsYou are encouraged to read JAX-RS spec (html version) to find out information not covered by this documentation. The JAX-RS introduces such terms as root resources, resource methods, sub-resources and sub-resource locators, message body readers and writers, etc. Please see the JAX-RS Basics page for more information. Support for Data BindingsJAX-RS MessageBodyReader and MessageBodyWriter can be used to create data bindings for reading and writing the data in a number of different formats. Compliant JAX-RS implementations are expected to support JAXB-annotated beans, JAXP Source objects, InputStreams, etc. In addition, CXF JAX-RS lets users reuse existing CXF DataBindings for working with JAXB, XBeans, Aegis and SDO. Please see the JAX-RS Data Bindings page for more information. Client APIJAX-RS 1.0 does not provide for the standard approach toward consuming pure HTTP-based services thus CXF JAX-RS provides a comprehensive support for developing RESTful clients by introducing 3 flavors of the client API : proxy-based, HTTP-centric and XML-centric. Please see the JAX-RS Client API page for more information. Support for MultipartsMultiparts can be handled in a number of ways. CXF core runtimes provides an advanced support for handling attachments and CXF JAX-RS builds upon it. Please see the JAX-RS Multiparts page for more information. XPath and XSLTXPath and XSLT are promoted and treated as first-class citizens in CXF JAX-RS. These technologies can be very powerful when generating complex data or retrieving data of interest out of complex XML fragments. XPath supportXPath is supported on the server and client sides with the help of XMLSource utility class. Please see above how http-centric WebClients can use XPath, here is an example for the server side : @Path("/root") public class Root { @POST public void post(XMLSource source) { String value = source.getProperty("/books/book/@name"); } } Users have an option to hide XPath expressions, by registering an XPathProvider, either on client or server sides. For example : XPathProvider provider = new XPathProvider(); provider.setGlobalExpression("/books/book[position() = 1]"); WebClient wc = WebClient.create("http://aggregated/data", Collections.singletonList(provider)); Book b = wc.get(Book.class); XSLT supportXSLT is currently supported by XSLTJaxbProvider. This provider works in tandem with JAXB and can be used to produce pretty much any format, including non-XML ones. Likewise, it can be used to extract XML data out of incoming XML fragments, either on the client or server sides. XSLTJaxbProvider can be configured to handle input or output data, scoped by media types if needed. For example, one may configure it such that one template handles "application/xml" formats only while the other one handles "application/json" writes only. XSLTJaxbProvider uses an injected JAX-RS UriInfo to inject all the usual JAX-RS information like template or query parameters into a given XSLT template. For example, given this resource method definition : @Path("/root") public class Root { @GET @Path("{id}") public Book get(@PathParam("id") String id, @QueryParam("name") String name) { return getBook(id, name); } } an XSLT template processing the JAXB-driven serialization of a Book instance will have parameters with name 'id' and 'name' injected. Note that when XSLTJaxbProvider is used on the client side, it may not always be possible for template parameters be injected in cases when http-centric clients are used (as opposed to proxies). For example : WebClient client = WebClient.create("http://books"); client.path("/store/1").get(); it is not possible to deduce that '1' represents a template parameter in the "/store/1" _expression_. However, one can use the following code instead if '1' needs to be available to XSLT templates : WebClient client = WebClient.create("http://books"); client.path("/store/{id}", 1).get(); Support for Complex Search QueriesUsing query parameter beans provides for a way to capture all the search requirements which can be expressed by enumerating simple name/value pairs, example, a query such as '?name=CXF&version=2.3' can be captured by a bean containing setName and setVersion methods. This 'template' bean can be used in the code to compare it against all the available local data. CXF JAXRS (since 2.3) supports another option for users to do the advanced search queries based on the Feed Item Query Language(FIQL). Please see the JAX-RS Advanced Features page for more information. DebuggingOne may want to use a browser to test how a given HTTP resource reacts to different HTTP Accept or Accept-Language header values and request methods. For example, if a resource class supports a "/resource" URI then one can test the resource class using one of the following queries : > GET /resource.xml The runtime will replace '.xml' or '.en' with an appropriate header value. For it to know the type or language value associated with a given URI suffix, some configuration needs to be done. Here's an example how to do it in Spring : <jaxrs:server id="customerService" address="/"> <jaxrs:serviceBeans> <bean class="org.apache.cxf.jaxrs.systests.CustomerService" /> </jaxrs:serviceBeans> <jaxrs:extensionMappings> <entry key="json" value="application/json"/> <entry key="xml" value="application/xml"/> </jaxrs:extensionMappings> <jaxrs:languageMappings/> </jaxrs:server> CXF also supports a _type query as an alternative to appending extensions like '.xml' to request URIs : > GET /resource?_type=xml Overriding a request method is also easy: > GET /resource?_method=POST Alternatively, one cam specify an HTTP header X-HTTP-Method-Override : > POST /books For example, at the moment http-centric client API does not support arbitrary HTTP verbs except for those supported Please see the Debugging and Logging page for more information on how to debug and log the service calls in CXF. LoggingMany of the existing CXF features can be applied either to jaxrs:server or jaxrs:client. For example, to enable the logging of requests and responses, simply do: <beans xmlns:cxf="http://cxf.apache.org/core" xsi:schemaLocation="http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd"> <jaxrs:server> <jaxrs:features> <cxf:logging/> </jaxrs:features> <jaxrs:server> </beans> Please make sure an "http://cxf.apache.org/core" namespace is in scope. Starting from CXF 2.3.0 it is also possible to convert log events into Atom entries and either push them to receivers or make available for polling. Please see the Debugging and Logging page for more information. Filters, Interceptors and InvokersIt is possible to intercept and affect the inbound and outbound calls with the help of CXF JAX-RS filters and/or CXF interceptors. Additionally, custom invokers offer an option to intercept a call immediately before a service bean is invoked. Please see the JAX-RS Filters page for more information. Advanced FeaturesCXF JAX-RS provides a number of advanced extensions such as the support for the JMS transport, one-way invocations (HTTP and JMS), the suspended invocations (HTTP and JMS), making existing code REST-aware by applying the external user models, etc. Please see the JAX-RS Advanced Features page for more information. Secure JAX-RS servicesA demo called samples\jax_rs\basic_https shows you how to do communications using HTTPS. Checking HTTP security headersIt is often containers like Tomcat or frameworks like Spring Security which deal with ensuring a current user is authenticated. Sometimes you might want to deal with the authentication manually. The easiest way to do it is to register a custom invoker or RequestHandler filter which will extract a user name and password like this (it will work only for Basic Authentication requests) : public class AuthenticationHandler implements RequestHandler { public Response handleRequest(Message m, ClassResourceInfo resourceClass) { AuthorizationPolicy policy = (AuthorizationPolicy)m.get(AuthorizationPolicy.class); policy.getUserName(); policy.getPassword(); // alternatively : // HttpHeaders headers = new HttpHeadersImpl(m); // access the headers as needed // authenticate the user return null; } } SecurityManager and IllegalAccessExceptionsIf java.lang.SecurityManager is installed then you'll likely need to configure the trusted JAXRS codebase with a 'suppressAccessChecks' permission for the injection of JAXRS context or parameter fields to succeed. For example, you may want to update a Tomcat catalina.policy with the following permission : grant codeBase "file:${catalina.home}/webapps/yourwebapp/lib/cxf.jar" { permission java.lang.reflect.ReflectPermission "suppressAccessChecks"; }; RedirectionStarting from CXF 2.2.5 it is possible to redirect the request or response call to other servlet resources by configuring CXFServlet or using CXF JAX-RS RequestDispatcherProvider. Please see the JAX-RS Redirection page for more information. Model-View-Controller supportXSLT JSP With the introduction of the RequestDispatcherProvider (see above) it is now possible for JAXRS service responses be redirected to JSP pages for further processing. Please see this beans.xml. In addition to 'resourcePath' and 'dispatcherName' properties, one can set a 'scope' property which has two possible values, 'request' and 'session' with 'request' being the default value. It affects the way the JSP code can retrieve parameters passed to it by the RequestDispatcherProvider. If it is a 'request' scope then all the parameters are set as the attributes on the current HTTP request, if it is a session then they're set as the attributes on the current HTTP session. RequestDispatcherProvider sets the following parameters :
Service listings and WADL supportCXF JAX-RS supports WADL. CXF JAX-RS service endpoints can be listed in the service listings page and users can check the WADL documents. Please see the JAXRS Services Description page for more information. Configuring JAX-RS servicesJAX-RS services can be configured programmatically, from Spring or using CXFNonSpringJAXRSServlet. Please see the JAXRS Services Configuration page for more information. Matching the Request URIThere's a number of variables involved here. Lets assume you have a web application called 'rest'. CXFServlet's url-pattern is "/test/*". Finally, jaxrs:server's address is "/bar". Requests like /rest/test/bar or /rest/test/bar/baz will be delivered to one of the resource classes in a given jaxrs:server endpoint. For the former request be handled, a resource class with @Path("/") should be available, in the latter case - at least @Path("/") or more specific @Path("/baz"). The same requirement can be expressed by having a CXFServlet with "/*" and jaxrs:server with "/test/bar". When both CXFServlet and jaxrs:server use "/" then it's a root resource class which should provide a @Path with at least "/test/bar" for the above requests be matched. Generally, it can be a good idea to specify the URI segments which are more likely to change now and then with CXFServlets or jaxrs:server. Combining JAX-WS and JAX-RSCXF JAX-RS tries to make it easy for SOAP developers to experiment with JAX-RS and combine both JAX-WS and JAX-RS in the same service bean when needed. Please see the JAX-RS and JAX-WS page for more information. Here's a beans.xml showing how to have a single service class supporting both SOAP and REST-based invocations at the same time with the help of JAX-WS and JAX-RS : <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxrs="http://cxf.apache.org/jaxrs" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <!-- JAX-RS --> <jaxrs:server id="customerService" address="/"> <jaxrs:serviceBeans> <ref bean="customerService" /> </jaxrs:serviceBeans> </jaxrs:server> <!-- JAX-WS --> <jaxws:endpoint implementor="#customerService" address="/CustomerWorld" wsdlLocation="..."/> <bean id="customerService" class="demo.jaxrs.server.CustomerService" /> </beans> Either contract-first or Java-first approach can be used for JAX-WS. JAX-RS annotations can be added to the existing service class. Some custom providers may need to be created, depending on the complexity of the method signatures. When a WSDL-first approach is used then a document-literal-wrapped style may or may not be a good fit as the code generator unwraps all the types into a signature, for example : public class CustomerService { public void doIt(String a, String b) {...}; } By default JAX-RS may not be able to handle such methods as it requires that only a single parameter can be available in a signature that is not annotated by one of the JAX-RS annotations like @PathParam. So if @Path("/customers/{a}") public class CustomerService { public void doIt(@PathParam("a") String a, String b) {...}; } Note that CXF Continuations API is supported for both JAXWS and JAXRS services. Dealing with contextsWhen combining JAXWS and JAXRS, one may need to access some context information as part of processing a given request. At the moment, CXF JAXRS does not offer a context implementation which can be used to access a request-specific information common for both JAXWS and JAXRS requests, in cases when the same methods are used to handle both JAXWS and JAXRS requests. Please use a JAXWS WebServiceContext and JAXRS contexts or CXF JAXRS composite MessageContext : @Path("/customers") @WebService public class CustomerService { @Resource WebServiceContext jaxwsContext; @Resource MessageContext jaxrsContext; @WebMethod @POST public void doIt(String b) { isUserInRole(); }; private void isUserInRole() throws WebApplicationException { if (jaxwsContext.getSecurityContext() != null) { // soap invocation jaxwsContext.getSecurityContext().isUserInRole(theRole); } else { // http-only jaxrs one jaxrsContext.getSecurityContext().isUserInRole(theRole); } } } Note that injected context instances (jaxwsContext and jaxrsContext) are in fact thread-local proxies hence they will not be equal to null even if they do not represent a given request. For example, jaxrsContext will not be equal to null even if it's not a JAXWS invocation which is being processed at the moment. However, if say a (JAXWS or JAXRS) SecurityContext needs to be accessed then it will be set in, say, jaxwsContext only if it's a JAXWS/SOAP invocation. For this reason it can be handy using a composite CXF JAXRS MessageContext when accessing a JAXRS-specific context information when combining JAXWS and JAXRS as one can easily check if it's actually a JAXRS request by simply checking an individual context like SecurityContext or UriInfo for null. Using individual contexts like JAXRS SecurityContext might be less attractive : @WebService public class CustomerService { @Resource WebServiceContext jaxwsContext; // @Resource can be applied too @Context SecurityContext jaxrsSecurityContext; } as some methods of SecurityContext return boolean values so only throwing a runtime exception can reliably indicate that this context is actually not in scope. Note that if you do not share the same service methods between JAXRS and JAXWS invocations then you can directly access corresponding contexts : @Path("/customers") @WebService public class CustomerService { @Resource WebServiceContext jaxwsContext; @Resource MessageContext jaxrsContext; @WebMethod public void doItSoap(String b) { isUserInRole(jaxwsContext.getSecurityContext().getPrincipal()); }; @POST public void doItSoap(String b) { isUserInRole(jaxwsContext.getSecurityContext().getPrincipal()); } private void isUserInRole(Principal p) throws WebApplicationException { ... } } Another option is to avoid the use of contexts in the service code and deal with them in CXF interceptors or JAXRS filters. Sometimes it's possible to avoid the use of contexts altogether. For example, Spring Security can be used to secure a given service at an individual method level. JAX-RS and Spring AOPCXF JAX-RS is capable of working with AOP interceptors applied to resource classes from Spring. <beans xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd"> <import resource="classpath:META-INF/cxf/cxf.xml"/> <import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml"/> <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/> <jaxrs:server id="bookservice" address="/"> <jaxrs:serviceBeans> <ref bean="bookstore"/> <ref bean="bookstoreInterface"/> </jaxrs:serviceBeans> </jaxrs:server> <bean id="bookstore" class="org.apache.cxf.systest.jaxrs.BookStore"/> <bean id="bookstoreInterface" class="org.apache.cxf.systest.jaxrs.BookStoreWithInterface"/> <aop:config> <aop:aspect id="loggingAspect" ref="simpleLogger"> <aop:before method="logBefore" pointcut="execution(* org.apache.cxf.systest.jaxrs.BookStore*.*(..))"/> <aop:after-returning method="logAfter" pointcut="execution(* org.apache.cxf.systest.jaxrs.BookStore*.*(..))"/> </aop:aspect> </aop:config> <bean id="simpleLogger" class="org.apache.cxf.systest.jaxrs.SimpleLoggingAspect"/> </beans> Note that some AOP configuration is applied to two JAX-RS resource classes. By default Spring uses JDK dynamic proxies every time a class to be proxified implements at least one interface or CGLIB proxies otherwise. For example, here's how org.apache.cxf.systest.jaxrs.BookStoreWithInterface looks like : public interface BookInterface { @GET @Path("/thosebooks/{bookId}/") @Produces("application/xml") Book getThatBook(Long id) throws BookNotFoundFault; } public class BookStoreWithInterface extends BookStoreStorage implements BookInterface { public Book getThatBook(@PathParam("bookId") Long id) throws BookNotFoundFault { return doGetBook(id); } @Path("/thebook") public Book getTheBook(@PathParam("bookId") Long id) throws BookNotFoundFault { return doGetBook(id); } } In this case Spring will use a JDK proxy to wrap a BookStoreWithInterface class. As such it is important that a method which needs to be invoked such as getThatBook(...) is part of the interface. The other method, getTheBook() can not be dispatched to by a JAX-RS runtime as it's not possible to discover it through a JDK proxy. If this method also needs to be invoked then this method should either be added to the interface or CGLIB proxies have to be explicitly enabled (consult Spring AOP documentation for more details). For example :
<aop:config proxy-target-class="true"/>
Integration with Distributed OSGiDistributed OSGi RI is a CXF subproject. DOSGi mandates how registered Java interfaces can be exposed CXF JAX-RS implementations has been integrated with DOSGi RI 1.1-SNAPSHOT which makes it possible to expose Java interfaces as RESTful services and consume such services using a proxy-based client API. Please see DOSGI Reference page ('org.apache.cxf.rs' properties) and a greeter_rest sample for more information. Note that this demo can be run exactly as a SOAP-based greeter demo as it registers and consumes a similar (but) JAX-RS annotated GreeterService. In addition, this demo shows how one can register and consume a given interface (GreeterService2) without using explicit JAX-RS annotations but providing an out-of-band user model description. How to contributeCXF JAX-RS implementation sits on top of the core CXF runtime and is quite self-contained and isolated from other CXF modules such as jaxws and simple frontends. Please check this list and see if you are interested in fixing one of the issues. If you decide to go ahead then the fastest way to start is to
If you are about to submit a patch after building a trunk/rt/frontend/jaxrs, then please also run JAX-RS system tests in trunk/systests/jaxrs :
Change Notification Preferences
View Online
|
View Changes
|
Add Comment
|
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
- [CONF] Apache CXF Documentation > JAX-RS confluence
