...
CXF
...
has
...
an
...
initial
...
implementation
...
of
...
JAX-RS
...
(JSR-311):
...
Java
...
API
...
for
...
RESTfulWeb
...
Services.
...
JAX-RS
...
provides
...
a
...
more
...
standard
...
way
...
to
...
build
...
RESTful
...
services
...
in
...
Java.
...
JAX-RS
...
related
...
demos
...
are
...
located
...
under
...
samples\jax_rs
...
directory
...
(CXF
...
2.1
...
only).
...
Understanding
...
the
...
basics
...
You
...
are
...
encouraged
...
to
...
read
...
...
...
to
...
find
...
out
...
information
...
not
...
covered
...
by
...
this
...
documentation.
...
Resource
...
class
...
A
...
resource
...
class
...
is
...
a
...
Java
...
Class
...
annotated
...
with
...
JAX-RS
...
annotations
...
to
...
represent
...
a
...
Web
...
resource.
...
A
...
typical
...
resource
...
class
...
in
...
JAX-RS
...
looks
...
like
...
below:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} package demo.jaxrs.server; import java.util.HashMap; import java.util.Map; import javax.ws.rs.GET; import javax.ws.rs.ProduceMime; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriInfo; @Path("/customerservice/") @ProduceMime("application/xml") public class CustomerService { public CustomerService() { } @GET public Customers getCustomers() { ...... } @GET @Path("/customers/{id}") @ProduceMime("application/json") public Customer getCustomer(@PathParam("id") String id) { ...... } @PUT @Path("/customers/{id}") @ConsumeMime("application/xml") public Response updateCustomer(@PathParam("id") Long id, Customer customer) { ...... } @POST @Path("/customers") public Response addCustomer(Customer customer) { ...... } @DELETE @Path("/customers/{id}/") public Response deleteCustomer(@PathParam("id") String id) { ...... } @Path("/orders/{orderId}/") public Order getOrder(@PathParam("orderId") String orderId) { ...... } } {code} |
Customer
...
resource
...
class
...
can
...
handle
...
requests
...
starting
...
from
...
/customerservice.
...
When
...
/customerservice
...
request
...
is
...
matched
...
to
...
this
...
class,
...
its
...
getCustomers()
...
method
...
will
...
be
...
selected.
...
updateCustomer(),
...
deleteCustomer()
...
and
...
addCustomer()
...
are
...
used
...
to
...
serve
...
POST,
...
PUT
...
and
...
DELETE
...
requests
...
starting
...
from
...
/customerservice/customer,
...
while
...
getOrder()
...
method
...
delegates
...
the
...
handling
...
of
...
requests
...
like
...
/customerservice/orders/1
...
to
...
a
...
subresource
...
locator
...
Order.
...
ProduceMime
...
annotation
...
is
...
used
...
to
...
specify
...
the
...
format
...
of
...
the
...
response.
...
When
...
not
...
available
...
on
...
the
...
method,
...
it's
...
inherited
...
from
...
a
...
class,
...
and
...
if
...
it's
...
not
...
available
...
on
...
the
...
class
...
then
...
it's
...
inherited
...
from
...
a
...
corresponding
...
message
...
body
...
writer,
...
if
...
any.
...
Default
...
value
...
is
...
/
...
,
...
but
...
it's
...
recommended
...
that
...
some
...
definite
...
value
...
is
...
specified.
...
The
...
same
...
applies
...
to
...
ConsumeMime,
...
only
...
it's
...
message
...
body
...
readers
...
are
...
checked
...
as
...
the
...
last
...
resort.
...
For
...
example,
...
getCustomers()
...
method
...
inherits
...
the
...
ProduceMime
...
annotation
...
from
...
its
...
class,
...
while
...
getCustomer()
...
method
...
overrides
...
it
...
with
...
its
...
own
...
value.
...
@Path
@Path annotation is applied to resource classes or methods. The value of @Path annotation is a relative URI path follows the URI Template format.
More information about Path annotations can be found from JAX-RS spec section 2.3.
HTTP Method
JAX-RS specification defines a number of annotations such as @GET, @PUT, @POST and @DELETE. Using an @HttpMethod designator, one can create a custom annotation such as @Update or @Patch
Return types
Either javax.ws.rs.core.Response
...
or
...
custom
...
type
...
can
...
be
...
returned.
...
javax.ws.rs.core.Response
...
can
...
be
...
used
...
to
...
set
...
the
...
HTTP
...
response
...
code,
...
headers
...
and
...
entity.
Exception handling
One can either throw an unchecked WebApplicationException or return Response with a proper error code set.
The former option may be a better option when no JAX-RS types can be added to method signatures.
For example :
Code Block | ||||
---|---|---|---|---|
| ||||
h3. Exception handling
One can either throw an unchecked WebApplicationException or return Response with a proper error code set.
The former option may be a better option when no JAX-RS types can be added to method signatures.
For example :
{code:java}
@Path("/customerservice/")
public class CustomerService {
@PUT
@Path("/customers/{id}")
public Response updateCustomer(@PathParam("id") Long id, Customer customer) {
return Response.status(errorCode).build();
}
@POST
@Path("/customers")
public Customer addCustomer(Customer customer) {
throw new WebApplicationException(errorCode);
}
}
|
Dealing with Parameters
PathParam annotation is used to map a given Path template variable to a method parameter.
For example :
Code Block | ||||
---|---|---|---|---|
| ||||
{code} h2. Dealing with Parameters PathParam annotation is used to map a given Path template variable to a method parameter. For example : {code:java} @Path("/customer/{id}") public class CustomerService { @PUT @Path("{name}") public Response updateCustomer(@PathParam("id") Long id, @PathParam("name") String name) { ... } } {code} |
In
...
this
...
case
...
a
...
template
...
variable
...
id
...
available
...
from
...
a
...
root
...
class
...
annotation
...
is
...
mapped
...
to
...
a
...
parameter
...
of
...
type
...
Long,
...
while
...
a
...
name
...
variable
...
is
...
mapped
...
to
...
a
...
parameter
...
of
...
type
...
String.
...
Paramaters
...
can
...
be
...
of
...
type
...
String
...
or
...
of
...
any
...
type
...
that
...
have
...
constructors
...
accepting
...
a
...
String
...
argument
...
or
...
static
...
valueOf(String
...
s)
...
methods.
...
JAX-RS
...
PathSegment
...
is
...
also
...
supported.
...
QueryParam,
...
HttpHeader
...
and
...
CookieParam
...
annotations
...
are
...
also
...
supported.
...
Context
...
annotations
...
If
...
a
...
parameter
...
or
...
field
...
of
...
either
...
UriInfo
...
or
...
HttpHeaders
...
or
...
SecurityContext
...
or
...
one
...
of
...
the
...
Servlet
...
types
...
like
...
ServeltContext
...
or
...
MessageBodyWorkers
...
is
...
annotated
...
with
...
a
...
Context
...
annotation
...
then
...
CXF
...
will
...
provide
...
properly
...
initialized
...
instances
...
to
...
the
...
application
...
code.
...
Note
...
that
...
if
...
fields
...
are
...
annotated
...
with
...
Context
...
then
...
care
...
should
...
be
...
taken
...
for
...
singleton
...
resource
...
classes
...
as
...
CXF
...
does
...
not
...
support
...
yet
...
a
...
thread-local
...
injection
...
of
...
Context
...
fields.
...
Injection
...
of
...
contexts
...
into
...
message
...
body
...
providers
...
is
...
not
...
supported
...
yet.
...
Example
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @Path("/customer") public class CustomerService { @Context ServletContext sc; @Context SecurityContext sc; @PUT public Response updateCustomer(@Context UriInfo u, @Context HttpHeader h, Customer c) { ... } } {code} h2. Annotation inheritance Most of the |
Annotation inheritance
Most of the JAX-RS
...
annotations
...
can
...
be
...
inherited
...
from
...
either
...
an
...
interface
...
or
...
a
...
superclass.
...
JAX-RS
...
specification
...
requires
...
that
...
only
...
the
...
ones
...
applied
...
to
...
methods
...
can
...
be
...
inherited.
...
For
...
example
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} public interface CustomerService { @PUT @Path("/customers/{id}") Response updateCustomer(Long id, Customer customer) { return Response.status(errorCode).build(); } @POST @Path("/customers") Customer addCustomer(Customer customer) { throw new WebApplicationException(errorCode); } } {code} @Path("/customerservice/") public class Customers implements CustomerService { public Response updateCustomer(@PathParam("id"), Customer customer) { return Response.status(errorCode).build(); } public Customer addCustomer(Customer customer) { throw new WebApplicationException(errorCode); } } {code} Note that annotations applied to the interface are inherited. CXF is not capable yet of inheriting the annotations applied to parameters such as PathParam so at the moment they need to be specified anyway at the root class level. Similarly annotations can be inherited from super-classes. CXF can inherit annotations applied directly to super-classes such as |
Note that annotations applied to the interface are inherited. CXF is not capable yet of inheriting the annotations applied to parameters such as PathParam so at the moment they need to be specified anyway at the root class level.
Similarly annotations can be inherited from super-classes.
CXF can inherit annotations applied directly to super-classes such as @Path("/customerservice/")
...
which
...
is
...
applied
...
to
...
the
...
Customers
...
class
...
above.
...
It
...
may
...
support
...
the
...
same
...
type
...
of
...
inheritance
...
for
...
interfaces
...
too.
...
Note
...
this
...
is
...
not
...
JAX-RS
...
compliant.
...
Sub-resource
...
locators.
...
A
...
method
...
of
...
a
...
resource
...
class
...
that
...
is
...
annotated
...
with
...
@Path
...
becomes
...
a
...
sub-resource
...
locator
...
when
...
an
...
annotation
...
with
...
an
...
HttpMethod
...
designator
...
like
...
@GET
...
is
...
not
...
present.
...
Sub-resource
...
locators
...
are
...
used
...
to
...
further
...
resolve
...
the
...
object
...
that
...
will
...
handle
...
the
...
request.
...
They
...
can
...
delegate
...
to
...
other
...
sub-resource
...
locators.
...
In
...
the
...
example
...
below,
...
getOrder
...
method
...
is
...
a
...
sub-resource
...
locator:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @Path("/customerservice/") public class CustomerService { @Path("/orders/{orderId}/") public Order getOrder(@PathParam("orderId") String orderId) { ...... } } @XmlRootElement(name = "Order") public class Order { private long id; public Order() { } public long getId() { return id; } @GET @Path("products/{productId}/") public Product getProduct(@PathParam("productId")int productId) { ...... } } {code} |
A
...
HTTP
...
GET
...
request
...
to
...
http://localhost:9000/customerservice/orders/223/products/323
...
is
...
dispatched
...
to
...
getOrder
...
method
...
first.
...
If
...
the
...
Order
...
resource
...
whose
...
id
...
is
...
223
...
is
...
found,
...
the
...
Order
...
223
...
will
...
be
...
used
...
to
...
further
...
resolve
...
Product
...
resource.
...
Eventually,
...
a
...
Product
...
323
...
that
...
belongs
...
to
...
Order
...
223
...
is
...
returned.
...
Message
...
Body
...
Providers
...
JAX-RS
...
relies
...
on
...
MessageBodyReader
...
and
...
MessageBodyWriter
...
implementations
...
to
...
serialize
...
and
...
de-serialize
...
Java
...
types.
...
JAX-RS
...
requires
...
that
...
certain
...
types
...
has
...
to
...
be
...
supported
...
out
...
of
...
the
...
box.
...
By
...
default,
...
CXF
...
supports
...
String,
...
byte[],
...
InputStream,
...
File,
...
JAXP
...
Source,
...
JAXB-annotated
...
types
...
with
...
application/xml
...
and
...
application/json
...
formats
...
(see
...
below).
...
JAX-RS
...
MultivaluedMap
...
is
...
also
...
supported
...
for
...
form
...
contents.
...
Support
...
for
...
other
...
types
...
like
...
Reader
...
and
...
StreamingOutput
...
is
...
on
...
the
...
way.
...
Custom Message Body Providers
It's
...
likely
...
that
...
a
...
given
...
application
...
may
...
need
...
to
...
deal
...
with
...
types
...
which
...
are
...
not
...
supported
...
by
...
default.
...
Alternatively,
...
developers
...
may
...
want
...
to
...
provide
...
a
...
more
...
efficient
...
support
...
for
...
handling
...
default
...
types
...
such
...
as
...
InputStream.
...
Here's
...
an
...
example
...
of
...
a
...
custom
...
MessageBodyReader
...
for
...
InputStream
...
(0.7
...
jax-rs
...
api)
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @ConsumeMime("application/octet-stream") @Provider public class InputStreamProvider implements MessageBodyReader<InputStream> { public boolean isReadable(Class<InputStream> type, Type genericType, Annotation[] annotations) { return InputStream.class.isAssignableFrom(type); } public InputStream readFrom(Class<InputStream> clazz, Type t, MediaType mt, Annotation[] a, MultivaluedMap<String, String> headers, InputStream is) throws IOException { return new FilterInputStream(is) { @Override public int read(byte[] b) throws IOException { // filter out some bytes } } } } {code} |
and
...
here's
...
an
...
example
...
of
...
a
...
custom
...
MessageBodyWriter
...
for
...
Long
...
(0.7
...
jax-rs
...
api)
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @ProduceMime("text/plain") @Provider public class LongProvider implements MessageBodyWriter<Long> { public long getSize(Long l) { return -1; } public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations) { return long.class.isAssignableFrom(type) || Long.class.isAssignableFrom(type); } public void writeTo(Long l, Class<?> clazz, Type type, Annotation[] a, MediaType mt, MultivaluedMap<String, Object> headers, OutputStream os) throws IOException { os.write(l.toString().getBytes()); } {code} h3. Registering custom providers Putting @Provider annotation on the provider class is something that should lead to your provider being registered with the runtime. CXF does not support this feature yet. One can easily register a provider either from the Spring configuration : {code:xml} |
Registering custom providers
Putting @Provider annotation on the provider class is something that should lead to your provider being registered with the runtime. CXF does not support this feature yet. One can easily register a provider either from the Spring configuration :
Code Block | ||||
---|---|---|---|---|
| ||||
<beans>
<jaxrs:server id="customerService" address="/">
<jaxrs:serviceBeans>
<bean class="org.CustomerService" />
</jaxrs:serviceBeans>
<jaxrs:entityProviders>
<bean ref="isProvider" />
<bean ref="longProvider" />
</jaxrs:entityProviders>
<bean id="isProvider" class="com.bar.providers.InputStreamProvider"/>
<bean id="longProvider" class="com.bar.providers.LongProvider"/>
</jaxrs:server>
</beans>
|
Please
...
note
...
that
...
once
...
CXF
...
is
...
updated
...
to
...
support
...
a
...
0.7
...
version
...
of
...
JAX-RS
...
api,
...
<jaxrs:entityProviders>
...
will
...
be
...
changed
...
to
...
<jaxrs:providers>.
...
JAX-RS
...
supports
...
different
...
types
...
of
...
providers
...
and
...
having
...
a
...
single
...
<jaxrs:providers>
...
container
...
is
...
in
...
line
...
with
...
the
...
way
...
other
...
JAX-RS
...
implementations
...
discover
...
providers
...
by
...
checking
...
for
...
@Provider
...
annotations
...
only.
...
See
...
below
...
a
...
more
...
complete
...
beans.xml
...
definition.
Content type negotiation
One of the coolest thing of REST is that the same resource can be served using multiple representations. @ProduceMime and @ConsumeMime annotations are used to declare the supported request and response media types.
JAXB support
The request and response can be marshaled and unmarshaled to/from Java object using JAXB. The Java object needs to be marked with @XmlRootElement annotation. For example:
Code Block | ||||
---|---|---|---|---|
| ||||
{code} h2. Content type negotiation One of the coolest thing of REST is that the same resource can be served using multiple representations. @ProduceMime and @ConsumeMime annotations are used to declare the supported request and response media types. h3. JAXB support The request and response can be marshaled and unmarshaled to/from Java object using JAXB. The Java object needs to be marked with @XmlRootElement annotation. For example: {code:java} @XmlRootElement(name = "Customer") public class Customer { private String name; private long id; public Customer() { } public void setName(String n) { name = n; } public String getName() { return name; } public void setId(long i) { id = i; } public long getId() { return id; } } {code} |
In
...
the
...
example
...
below,
...
the
...
Customer
...
object
...
returned
...
by
...
getCustomer
...
is
...
marshaled
...
using
...
JAXB
...
data
...
binding:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @Path("/customerservice/") public class CustomerService { @GET @Path("/customers/{customerId}/") public Customer getCustomer(@PathParam("customerId") String id) { .... } } {code} |
The
...
wire
...
representation
...
of
...
Customer
...
object
...
is:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @Path("/customerservice/") <Customer> <id>123</id> <name>John</name> </Customer> {code} |
To
...
work
...
with
...
collections,
...
you
...
need
...
to
...
define
...
an
...
object
...
collection
...
type.
...
For
...
example:
Code Block |
---|
} @XmlRootElement(name = "Customers") public class Customers { private Collection<Customer> customers; public Collection<Customer> getCustomer() { return customers; } public void setCustomer(Collection<Customer> c) { this.customers = c; } } @Path("/customerservice/") public class CustomerService { @GET @Path("/customers/") public Customers getCustomers() { .... } } {code} |
JSON support
Following code returns a Customer object that is marshaled to JSON format:
Code Block |
---|
h3. JSON support Following code returns a Customer object that is marshaled to JSON format: {code} @Path("/customerservice/") public class CustomerService { @ProduceMime("application/json") @GET @Path("/customers/{customerId}/") public Customer getCustomer(@PathParam("customerId") String id) { .... } {code} |
The
...
wire
...
representation
...
of
...
Customer
...
object
...
is:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java}
{"Customer ":{"id":"123","name":"john"}}
|
Source support
You can also receive the request as a Source object or return a Source object as response:
Code Block | ||||
---|---|---|---|---|
| ||||
{code} h3. Source support You can also receive the request as a Source object or return a Source object as response: {code:java} @Path("/customerservice/") public class CustomerService { @PUT @Path("/customers/") public javax.xml.transform.Source updateCustomer(javax.xml.transform.Source ds) { .... } } {code} h2. Secure JAX-RS services A demo called |
Advanced Content type negotiation
CXF provides a partial support for an advanced content type negotiation by handling If-Match headers and ETags in its JAX-RS Request implementation. Neither If-Modified-Since nor Vary headers are currently supported.
Secure JAX-RS services
A demo called samples\jax_rs\basic_https
...
shows
...
you
...
how
...
to
...
do
...
communications
...
using
...
HTTPS.
...
Configuring JAX-RS
...
services
Configuring JAX-RS
...
services
...
programmatically
...
You
...
can
...
create
...
a
...
JAX-RS
...
RESTful
...
service
...
by
...
using
...
...
from
...
the
...
cxf-rt-frontend-jaxrs
...
package:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean(); sf.setResourceClasses(CustomerService.class); sf.setAddress("http://localhost:9000/"); sf.create(); {code} |
A
...
couple
...
things
...
to
...
note:
...
- The
...
- JAXRSServerFactoryBean
...
- creates
...
- a
...
- Server
...
- inside
...
- CXF
...
- which
...
- starts
...
- listening
...
- for
...
- requests
...
- on
...
- the
...
- URL
...
- specified.
...
- By
...
- default,
...
- the
...
- JAX-RS
...
- runtime
...
- is
...
- responsible
...
- for
...
- the
...
- lifecycle
...
- of
...
- resource
...
- classes,
...
- default
...
- lifecycle
...
- is
...
- per-request.
...
- You
...
- can
...
- set
...
- the
...
- lifecycle
...
- to
...
- singleton
...
- by
...
- using
...
- following
...
- line:
...
Code Block java java sf.setResourceProvider(BookStore.class, new SingletonResourceProvider());
...
- If you prefer not to let the JAX-RS
...
- runtime
...
- to
...
- handle
...
- the
...
- resource
...
- class
...
- lifecycle
...
- for
...
- you
...
- (for
...
- example,
...
- it
...
- might
...
- be
...
- the
...
- case
...
- that
...
- your
...
- resource
...
- class
...
- is
...
- created
...
- by
...
- other
...
- containers
...
- such
...
- as
...
- Spring),
...
- you
...
- can
...
- do
...
- following:
...
Code Block java java JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean(); CustomerService cs = new CustomerService(); sf.setServiceBeans(cs); sf.setAddress("http://localhost:9080/"); sf.create();
...
Configuring JAX-RS
...
services
...
in
...
container
...
with
...
Spring
...
configuration
...
file.
...
web.xml
Code Block | ||||
---|---|---|---|---|
| ||||
{code:xml}
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
|
beans.xml
Code Block | ||||
---|---|---|---|---|
| ||||
{code} h3. beans.xml {code:xml} <?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" 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"> <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="customerService" address="/"> <jaxrs:serviceBeans> <bean<ref refbean="customerService" /> </jaxrs:serviceBeans> </jaxrs:server> <bean id="customerService" class="demo.jaxrs.server.CustomerService" /> </beans> {code} h2. Combining |
Combining JAX-WS
...
and
...
JAX-RS
...
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
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:xml} <?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> <bean<ref refbean="#customerServicecustomerService" /> </jaxrs:serviceBeans> </jaxrs:server> <!-- JAX-WS --> <jaxws:endpoint implementor="#customerService" address="/CustomerWorld" wsdlLocation="..."/> <bean id="customerService" class="demo.jaxrs.server.CustomerService" /> </beans> {code} |
If
...
demo.jaxrs.server.CustomerService
...
was
...
used
...
to
...
serve
...
SOAP
...
requests
...
then
...
either
...
contract-first
...
or
...
Java-first
...
could've
...
been
...
used.
...
JAX-RS
...
annotations
...
can
...
be
...
added
...
to
...
the
...
existing
...
service
...
class.
...
Some
...
custome
...
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
...
z
...
good
...
fit
...
as
...
the
...
code
...
generator
...
unwraps
...
all
...
the
...
types
...
into
...
a
...
signature,
...
for
...
example
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} public class CustomerService { void doIt(String a, String b) {...}; } {code} By default |
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
...
a
...
'String
...
a'
...
parameter
...
can
...
be
...
mapped
...
to
...
a
...
@Path
...
template
...
variable
...
or
...
one
...
of
...
the
...
query
...
segments
...
then
...
this
...
signature
...
won't
...
need
...
to
...
be
...
changed
...
:
Code Block | ||||
---|---|---|---|---|
| ||||
{code:java} @Path("/customers/{a}") public class CustomerService { void doIt(@PathParam("a") String a, String b) {...}; } {code} For methods returning |
For methods returning 'void',
...
a
...
simple
...
custom
...
provider
...
can
...
be
...
created
...
which
...
will
...
basically
...
be
...
a
...
no-op
...
implementation.
JAX-RS and Spring AOP
CXF JAX-RS is capable of working with AOP interceptors applied to resource classes from Spring.
For example :
Code Block | ||||
---|---|---|---|---|
| ||||
<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 :
Code Block | ||||
---|---|---|---|---|
| ||||
public interface BookInterface {
@GET
@Path("/thosebooks/{bookId}/")
@ProduceMime("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)