이 콘텐츠는 선택한 언어로 제공되지 않습니다.
Chapter 2. Developing JAX-RS Web Services
JAX-RS is the Java API for RESTful web services. It provides support for building web services using REST, through the use of annotations. These annotations simplify the process of mapping Java objects to web resources.
RESTEasy is the Red Hat JBoss Enterprise Application Platform 7 implementation of JAX-RS and is fully compliant with the JSR-000339 Java API for RESTful Web Services 2.0 specification. It also provides additional features to the specification.
To get started with JAX-RS, see the helloworld-rs
, jaxrs-client
, and kitchensink
quickstarts that ship with Red Hat JBoss Enterprise Application Platform 7.
JBoss EAP does not support the resteasy-crypto
, resteasy-yaml-provider
, and jose-jwt
modules.
2.1. JAX-RS Application 링크 복사링크가 클립보드에 복사되었습니다!
When creating providers and web resources, you have the following options for declaring them:
-
Simple subclassing of
javax.ws.rs.core.Application
without aweb.xml
file. -
Using a
web.xml
file. -
Subclassing
javax.ws.rs.core.Application
and providing a custom implementation.
2.1.1. Simple Subclassing javax.ws.rs.core.Application 링크 복사링크가 클립보드에 복사되었습니다!
You can use the javax.ws.rs.core.Application
class to create a subclass that declares those providers and web resources. This class is provided by the RESTEasy libraries included with JBoss EAP.
To configure a resource or provider using javax.ws.rs.core.Application
, simply create a class that extends it and add an @ApplicationPath
annotation.
Example: Application Class
2.1.2. Using web.xml 링크 복사링크가 클립보드에 복사되었습니다!
Alternatively, if you do not want to create a class that extends javax.ws.rs.core.Application
, you can add the following to your web.xml
file.
Example: web.xml
2.1.3. Subclassing javax.ws.rs.core.Application with a Custom Implementation 링크 복사링크가 클립보드에 복사되었습니다!
When subclassing javax.ws.rs.core.Application
you can choose to provide a custom implementation for any of the existing methods. The getClasses
and getSingletons
methods return a collection of classes or singletons that must be included in the published JAX-RS application.
-
If either
getClasses
andgetSingletons
returns a non-empty collection, only those classes and singletons are published in the JAX-RS application. -
If both
getClasses
andgetSingletons
return an empty collection, then all root resource classes and providers that are packaged in the web application are included in the JAX-RS application. RESTEasy will then automatically discover those resources.
2.2. JAX-RS Client 링크 복사링크가 클립보드에 복사되었습니다!
2.2.1. JAX-RS 2.0 Client API 링크 복사링크가 클립보드에 복사되었습니다!
JAX-RS 2.0 introduces a new client API to send HTTP requests to remote RESTful web services. It is a fluent request-building API with 3 main classes:
-
Client
-
WebTarget
-
Response
The Client
interface is a builder of WebTarget instances. The WebTarget
represents a distinct URL or URL template to build subresource WebTargets or invoke requests on.
There are two ways to create a client: the standard way, or using the ResteasyClientBuilder
class. The advantage of using the ResteasyClientBuilder
class is that it provides a few more helper methods to configure your client.
Using the Standard Way to Create a Client
The following example shows one of the standard ways to create a client:
Client client = ClientBuilder.newClient();
Client client = ClientBuilder.newClient();
Alternatively, you can use another standard way to create a client as shown in the example below:
Client client = ClientBuilder.newBuilder().build(); WebTarget target = client.target("http://foo.com/resource"); Response response = target.request().get(); String value = response.readEntity(String.class); response.close(); // You should close connections!
Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://foo.com/resource");
Response response = target.request().get();
String value = response.readEntity(String.class);
response.close(); // You should close connections!
Using the ResteasyClientBuilder Class to Create a Client
ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target("http://foo.com/resource");
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");
RESTEasy automatically loads a set of default providers that includes all classes listed in the META-INF/services/javax.ws.rs.ext.Providers
file. Additionally, you can manually register other providers, filters, and interceptors through the configuration object provided by the method call Client.configuration()
. Configuration also lets you set configuration properties that might be needed.
Each WebTarget
has a configuration instance that inherits the components and properties registered with the parent instance. This lets you set specific configuration options for each target resource, for example, the username and password.
Using RESTEasy Client Classes
You must add the following dependency for users of the Maven project:
<dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> <version>VERSION_IN_EAP</version> </dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>VERSION_IN_EAP</version>
</dependency>
See the jaxrs-client
and resteasy-jaxrs-client
quickstarts that ship with JBoss EAP for working examples that use the RESTEasy client classes.
Client-side Filters
The client side has two types of filters:
ClientRequestFilter
-
A
ClientRequestFilter
runs before an HTTP request is sent over the wire to the server. TheClientRequestFilter
is also allowed to abort the request execution and provide a canned response without going over the wire to the server. ClientResponseFilter
-
A
ClientResponseFilter
runs after a response is received from the server, but before the response body is unmarshalled. TheClientResponseFilter
can modify the response object before it is handed to the application code. For example:
Register Client-side Filters to the Client Request
The following example shows how to register the client-side filters to the client request:
client = ClientBuilder.newClient(); WebTarget base = client.target(generateURL("/") + "get"); base.register(ClientExceptionsCustomClientResponseFilter.class).request("text/plain").get();
client = ClientBuilder.newClient();
WebTarget base = client.target(generateURL("/") + "get");
base.register(ClientExceptionsCustomClientResponseFilter.class).request("text/plain").get();
Client-side Cache
RESTEasy has the ability to set up a client-side cache. This cache looks for cache-control headers sent back with a server response. If the cache-control headers specify that the client is allowed to cache the response, RESTEasy caches it within the local memory.
ResteasyWebTarget target = client.target(generateBaseUrl()); target.register(BrowserCacheFeature.class);
ResteasyWebTarget target = client.target(generateBaseUrl());
target.register(BrowserCacheFeature.class);
Chunked Encoding Support
RESTEasy provides the client API the ability to specify that requests should be sent in a chunked transfer mode. There are two ways of specifying the chunked transfer mode, as shown below.
You can configure the
org.jboss.resteasy.client.jaxrs.ResteasyWebTarget
to send all the requests in chunked mode:ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target("http://localhost:8081/test"); target.setChunked(b.booleanValue()); Invocation.Builder request = target.request();
ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target("http://localhost:8081/test"); target.setChunked(b.booleanValue()); Invocation.Builder request = target.request();
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Alternatively, you can configure a particular request to be sent in chunked mode:
ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target("http://localhost:8081/test"); ClientInvocationBuilder request = (ClientInvocationBuilder) target.request(); request.setChunked(b);
ResteasyClient client = new ResteasyClientBuilder().build(); ResteasyWebTarget target = client.target("http://localhost:8081/test"); ClientInvocationBuilder request = (ClientInvocationBuilder) target.request(); request.setChunked(b);
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Unlike the
javax.ws.rs.client.Invocation.Builder
class,org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder
is a RESTEasy class.
The ability to send the requests in chunked mode depends on the underlying transport layer. In particular, it depends on the implementation of the org.jboss.resteasy.client.jaxrs.ClientHttpEngine
class being used. Currently, only the default implementation ApacheHttpClient43Engine
and the previous implementation ApacheHttpClient4Engine
support the chunked mode. Both these are available in the org.jboss.resteasy.client.jaxrs.engines
package. See section Implementing RESTEasy with HTTP Client for more information.
2.2.2. Implementing RESTEasy with HTTP Client 링크 복사링크가 클립보드에 복사되었습니다!
Network communication between the client and server is handled by default in RESTEasy. It uses the HttpClient
from the Apache HttpComponents
project. The interface between the RESTEasy client framework and the network is defined by the ClientHttpEngine
interface.
RESTEasy ships with four implementations of this interface. The default implementation is ApacheHttpClient43Engine
. This implementation uses Apache 4.3.
ApacheHttpClient4Engine
is an implementation that uses the versions earlier than Apache 4.3. This class provides backward compatibility. RESTEasy automatically selects one of these two ClientHttpEngine
implementations based on the detection of the Apache version. InMemoryClientEngine
is an implementation that dispatches requests to a server in the same JVM, and URLConnectionEngine
is an implementation that uses java.net.HttpURLConnection
.
A client executor can be passed to a specific ClientRequest
:
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();
ResteasyClient client = new
ResteasyClientBuilder().httpEngine(engine).build();
RESTEasy and HttpClient
make the default decisions to use the client framework without referencing HttpClient
. However, for some applications it might be necessary to drill down into the HttpClient
details. ApacheHttpClient43Engine
and ApacheHttpClient4Engine
can be supplied with an instance of org.apache.http.client.HttpClient
and org.apache.http.protocol.HttpContext
, which can carry additional configuration details into the HttpClient
layer. For example, authentication can be configured as follows:
HttpContextProvider
is an interface provided by RESTEasy, using which you can supply a custom HttpContext
to the ApacheHttpClient43Engine
and ApacheHttpClient4Engine
implementations.
It is important to understand the difference between releasing a connection and closing a connection. Releasing a connection makes it available for reuse. Closing a connection frees its resources and makes it unusable.
RESTEasy releases the connection without notification. The only counter example is the case in which the response is an instance of InputStream
, which must be closed explicitly.
On the other hand, if the result of an invocation is an instance of Response
, the Response.close()
method must be used to release the connection.
WebTarget target = client.target("http://localhost:8081/customer/123"); Response response = target.request().get(); System.out.println(response.getStatus()); response.close();
WebTarget target = client.target("http://localhost:8081/customer/123");
Response response = target.request().get();
System.out.println(response.getStatus());
response.close();
You may execute this in a try-finally
block. Releasing a connection makes it available for another use. It does not normally close the socket.
ApacheHttpClient4Engine.finalize()
closes any open sockets, if it created the HttpClient
that it has been using. It is not safe to rely on JDK to call finalize()
. If an HttpClient
is passed to the ApacheHttpClient4Executor
, the user must close the connections, as shown below:
HttpClient httpClient = new HttpClientBuilder.create().build(); ApacheHttpClient4Engine executor = new ApacheHttpClient4Engine(httpClient); ... httpClient.getConnectionManager().shutdown();
HttpClient httpClient = new HttpClientBuilder.create().build();
ApacheHttpClient4Engine executor = new ApacheHttpClient4Engine(httpClient);
...
httpClient.getConnectionManager().shutdown();
If ApacheHttpClient4Engine
has created its own instance of HttpClient
, it is not necessary to wait for finalize()
to close open sockets. The ClientHttpEngine
interface has a close()
method for this purpose.
Finally, if the javax.ws.rs.client.Client
class has created the engine automatically, call Client.close()
. This call cleans up any socket connections.
2.3. JAX-RS Request Processing 링크 복사링크가 클립보드에 복사되었습니다!
2.3.1. Asynchronous HTTP Request Processing 링크 복사링크가 클립보드에 복사되었습니다!
Asynchronous request processing allows you to process a single HTTP request using non-blocking input and output and, if required, in separate threads.
Consider an AJAX chat client in which you want to push and pull from both the client and the server. This scenario has the client blocking for a long time on the server’s socket, waiting for a new message. In case of synchronous HTTP processing, where the server is blocking on incoming and outgoing input and output, you have one separate thread consumed per client connection. This model of request processing consumes a lot of memory and valuable thread resources.
Asynchronous processing separates the connection accepting and the request processing operations. It allocates two different threads: one to accept the client connection; the other to handle heavy, time-consuming operations. In this model, the container works as follows:
- It dispatches a thread to accept a client connection, which is the acceptor.
- Then it hands over the request to the processing thread, which is the worker.
- Finally, it releases the acceptor thread.
The result is sent back to the client by the worker thread. Hence, the client’s connection remains open, thereby improving the server’s throughput and scalability.
2.3.1.1. Server Asynchronous Response Processing 링크 복사링크가 클립보드에 복사되었습니다!
On the server side, asynchronous processing involves suspending the original request thread and initiating the request processing on a different thread, which releases the original server-side thread to accept other incoming requests.
2.3.1.1.1. AsyncResponse API 링크 복사링크가 클립보드에 복사되었습니다!
The JAX-RS 2.0 specification has added asynchronous HTTP support using two classes: the @Suspended
annotation and the AsyncResponse
interface.
Injecting an AsyncResponse
as a parameter to your JAX-RS method prompts RESTEasy to detach the HTTP request and response from the thread being executed currently. This ensures that the current thread does not try to automatically process the response.
The AsyncResponse
is the callback object. The act of calling one of the resume()
methods causes a response to be sent back to the client and also terminates the HTTP request. The following is an example of asynchronous processing:
2.3.1.2. AsyncInvoker Client API 링크 복사링크가 클립보드에 복사되었습니다!
Similarly, on the client side, asynchronous processing prevents blocking the request thread since no time is spent waiting for a response from the server. For instance, a thread that issued a request may also update a user interface component. If that thread is blocked waiting for a response, the user’s perceived performance of the application will suffer.
2.3.1.2.1. Using Future 링크 복사링크가 클립보드에 복사되었습니다!
In the code snippet below, the get()
method is called on the async()
method rather than the request. This changes the call mechanism from synchronous to asynchronous. Instead of responding synchronously, the async()
method returns a future
object. When you call the get()
method, the call is blocked until the response is ready. The future.get()
method will be returned whenever the response is ready.
2.3.1.2.2. Using InvocationCallback 링크 복사링크가 클립보드에 복사되었습니다!
The AsyncInvoker
interface allows you to register an object that will be called back when the asynchronous invocation is ready for processing. The InvocationCallback
interface provides two methods: completed()
and failed()
. The completed()
method is called whenever the processing is finished successfully and the response is received. Conversely, the failed()
method is called whenever the request processing is not successful.
2.4. Viewing RESTEasy Endpoints 링크 복사링크가 클립보드에 복사되었습니다!
You can use the read-resource
operation of the jaxrs
subsystem to view structured output of each RESTEasy endpoint. An example of the management CLI command and the expected outcome is provided below.
In the example above, the output information is grouped by the resource-class
and ordered as per the resource-path
:
-
resource-path
is the address to access the endpoint. -
resource-class
defines the class, where the endpoint is defined. -
rest-resource-paths
includes the Java methods that define the resource path, HTTP method, consumes and produces of the endpoint. -
java-method
specifies the name of the Java method and its parameters. It also contains information about the following JAX-RS annotations, if defined:@PathParam
,@QueryParam
,@HeaderParam
,@MatrixParam
,@CookieParam
,@FormParam
and@DefaultValue
.
Alternatively, you can use the read-resource
operation without the rest-resource
parameter defined and get the information about all the endpoints, as shown in the example below:
/deployment=DEPLOYMENT_NAME/subsystem=jaxrs:read-resource(include-runtime=true,recursive=true)
/deployment=DEPLOYMENT_NAME/subsystem=jaxrs:read-resource(include-runtime=true,recursive=true)
2.5. URL-Based Negotiation 링크 복사링크가 클립보드에 복사되었습니다!
2.5.1. Mapping Extensions to Media Types 링크 복사링크가 클립보드에 복사되었습니다!
Some clients, such as browsers, cannot use the Accept
and Accept-Language
headers to negotiate the representation media type or language. RESTEasy can map file name suffixes to media types and languages to deal with this issue.
To map media types to file extensions using the web.xml
file, you need to add a resteasy.media.type.mappings
context param and the list of mappings as the param-value
. The list is comma separated and uses colons (:
) to delimit the file extension and media type.
Example web.xml
Mapping File Extensions to Media Types
<context-param> <param-name>resteasy.media.type.mappings</param-name> <param-value>html : text/html, json : application/json, xml : application/xml</param-value> </context-param>
<context-param>
<param-name>resteasy.media.type.mappings</param-name>
<param-value>html : text/html, json : application/json, xml : application/xml</param-value>
</context-param>
2.5.2. Mapping Extensions to Languages 링크 복사링크가 클립보드에 복사되었습니다!
Some clients, such as browsers, cannot use the Accept
and Accept-Language
headers to negotiate the representation media type or language. RESTEasy can map file name suffixes to media types and languages to deal with this issue. Follow these steps to map languages to file extensions, in the web.xml
file.
To map media types to file extensions using the web.xml
file, you need to add a resteasy.language.mappings
context param and the list of mappings as the param-value
. The list is comma separated and uses colons (:
) to delimit the file extension and language type.
Example web.xml
Mapping File Extensions to Language Types
<context-param> <param-name>resteasy.language.mappings</param-name> <param-value> en : en-US, es : es, fr : fr</param-name> </context-param>
<context-param>
<param-name>resteasy.language.mappings</param-name>
<param-value> en : en-US, es : es, fr : fr</param-name>
</context-param>
2.6. Content Marshalling and Providers 링크 복사링크가 클립보드에 복사되었습니다!
2.6.1. Default Providers and Default JAX-RS Content Marshalling 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy can automatically marshal and unmarshal a few different message bodies.
Media Types | Java Types |
---|---|
| JAXB annotated classes |
| org.w3c.dom.Document |
* / * | java.lang.String |
* / * | java.io.InputStream |
| primitives, java.lang.String, or any type that has a String constructor, or static valueOf(String) method for input, toString() for output |
* / * | javax.activation.DataSource |
* / * | java.io.File |
* / * | byte |
| javax.ws.rs.core.MultivaluedMap |
2.6.1.1. Text Media Types and Character Sets 링크 복사링크가 클립보드에 복사되었습니다!
According to the JAX-RS specification, implementations must adhere to application-supplied character set metadata when writing responses. If a character set is not specified by the application or if the application specifies a character set that is not supported, then the implementations must use UTF-8 character set.
On the contrary, according to the HTTP specification, when no explicit charset parameter is provided by the sender, media subtypes of the text
type are defined to have a default charset value of ISO-8859-1
when received via HTTP. Data in character sets other than ISO-8859-1
or its subsets must be labeled with an appropriate charset value.
In the absence of a character set specified by a resource or resource method, RESTEasy uses UTF-8 as the character set for text media types. In order to do so, RESTEasy adds an explicit charset parameter to the content-type response header.
To specify the original behavior, in which UTF-8 is used for text media types but the explicit charset parameter is not appended, set the context parameter resteasy.add.charset
to false
. The default value of this parameter is true
.
Text media types include:
-
Media types with type
text
and any subtype. -
Media types with type
application
and subtype beginning withxml
. This includesapplication/xml-external-parsed-entity
andapplication/xml-dtd
.
2.6.2. Content Marshalling with @Provider classes 링크 복사링크가 클립보드에 복사되었습니다!
The JAX-RS specification allows you to plug in your own request/response body readers and writers. To do this, you annotate a class with @Provider
and specify the @Produces
types for a writer and @Consumes
types for a reader. You must also implement a MessageBodyReader/Writer
interface.
The RESTEasy ServletContextLoader
automatically scans the WEB-INF/lib
and classes directories for classes annotated with @Provider
, or you can manually configure them in the web.xml
file.
2.6.3. Providers Utility Class 링크 복사링크가 클립보드에 복사되었습니다!
javax.ws.rs.ext.Providers
is a simple injectable interface that allows you to look up MessageBodyReaders
, Writers
, ContextResolvers
, and ExceptionMappers
. It is very useful for implementing multipart providers and content types that embed other random content types.
A Providers
instance is injectable into MessageBodyReader
or Writers
:
2.6.4. Configuring Document Marshalling 링크 복사링크가 클립보드에 복사되었습니다!
XML document parsers are subject to a form of attack known as the XXE (XML eXternal Entity) attack, in which expanding an external entity causes an unsafe file to be loaded. For example, the following document could cause the /etc/passwd
file to be loaded.
By default, the RESTEasy built-in unmarshaller for org.w3c.dom.Document
documents does not expand external entities. It replaces them with an empty string. You can configure it to replace external entities with values defined in the DTD. This is done by setting the resteasy.document.expand.entity.references
context parameter to true
in the web.xml
file.
Example: Setting the resteasy.document.expand.entity.references
Context Parameter
<context-param> <param-name>resteasy.document.expand.entity.references</param-name> <param-value>true</param-value> </context-param>
<context-param>
<param-name>resteasy.document.expand.entity.references</param-name>
<param-value>true</param-value>
</context-param>
Another way of dealing with the problem is by prohibiting DTDs, which RESTEasy does by default. This behavior can be changed by setting the resteasy.document.secure.disableDTDs
context parameter to false
.
Example: Setting the resteasy.document.secure.disableDTDs
Context Parameter
<context-param> <param-name>resteasy.document.secure.disableDTDs</param-name> <param-value>false</param-value> </context-param>
<context-param>
<param-name>resteasy.document.secure.disableDTDs</param-name>
<param-value>false</param-value>
</context-param>
Documents are also subject to Denial of Service Attacks when buffers are overrun by large entities or too many attributes. For example, if a DTD defined the following entities, the expansion of &foo6;
would result in 1,000,000 foos.
By default, RESTEasy limits the number of expansions and the number of attributes per entity. The exact behavior depends on the underlying parser. The limit can be turned off by setting the resteasy.document.secure.processing.feature
context parameter to false
.
Example: Setting the resteasy.document.secure.processing.feature
Context Parameter
<context-param> <param-name>resteasy.document.secure.processing.feature</param-name> <param-value>false</param-value> </context-param>
<context-param>
<param-name>resteasy.document.secure.processing.feature</param-name>
<param-value>false</param-value>
</context-param>
2.6.5. Using MapProvider 링크 복사링크가 클립보드에 복사되었습니다!
You can use MapProvider
to accept and return a map with JAX-RS resources.
Example: Resource Accepting and Returning a Map
You can also send and receive maps to JAX-RS resources using the client.
Example: Client
2.6.6. Converting String Based Annotations to Objects 링크 복사링크가 클립보드에 복사되었습니다!
JAX-RS @*Param
annotations, including @QueryParam
, @MatrixParam
, @HeaderParam
, @PathParam
, and @FormParam
, are represented as strings in a raw HTTP request. These types of injected parameters can be converted to objects if these objects have a valueOf(String)
static method or a constructor that takes one String
parameter.
If you have a class where the valueOf()
method or the string constructor does not exist or is inappropriate for an HTTP request, the JAX-RS 2.0 specification provides the javax.ws.rs.ext.ParamConverterProvider
and javax.ws.rs.ext.ParamConverter
to help convert the message parameter value to the corresponding custom Java type. ParamConverterProvider
must be either programmatically registered in a JAX-RS runtime or must be annotated with @Provider
annotation to be automatically discovered by the JAX-RS runtime during a provider scanning phase.
For example: The steps below demonstrate how to create a custom POJO object. The conversion from message parameter value such as @QueryParam
, @PathParam
, @MatrixParam
, @HeaderParam
into POJO object is done by implementation of ParamConverter
and ParamConverterProvider
interfaces.
Create the custom POJO class.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create the custom POJO Converter class.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create the custom POJO Converter Provider class.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Create the custom MyResource class.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.6.7. Serializable Provider 링크 복사링크가 클립보드에 복사되었습니다!
Deserializing Java objects from untrusted sources is not safe. Therefore, org.jboss.resteasy.plugins.providers.SerializableProvider
is disabled by default. It is not recommended to use this provider.
2.6.8. JSON Provider 링크 복사링크가 클립보드에 복사되었습니다!
2.6.8.1. JsonFilter Support in RESTEasy Jackson2 링크 복사링크가 클립보드에 복사되었습니다!
JsonFilter
facilitates dynamic filtering by allowing you to annotate a class with @JsonFilter
. The following example defines mapping from the nameFilter
class to the filter instances, and then filtering out bean properties when serializing the instances to JSON format.
@JsonFilter
annotates the resource class to filter out the property that should not be serialized in the JSON response. To map the filter ID and instance, you must create another Jackson class and add the ID and filter instance map to it, as shown in the example below.
In the example above, the method modify()
takes care of filtering all properties except the name
property before writing the response. For this to work, RESTEasy must know about this mapping information. You can set the mapping information either in a WriterInterceptor
or a servlet filter, as shown in the examples below.
Example: Setting ObjectFilterModifier Using WriterInterceptor
Example: Setting ObjectFilterModifier Using Servlet Filter
Now, RESTEasy can get the ObjectFilterModifier
from the ThreadLocal
variable and configure it to modify ObjectWriter
before writing the response.
2.6.9. JAXB Providers 링크 복사링크가 클립보드에 복사되었습니다!
2.6.9.1. JAXB and XML Provider 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy provides JAXB provider support for XML.
@XmlHeader and @Stylesheet
RESTEasy provides setting an XML header using the @org.jboss.resteasy.annotations.providers.jaxb.XmlHeader
annotation.
Example: Using the @XmlHeader
Annotation
The @XmlHeader
ensures that the XML output has an XML-stylesheet header.
RESTEasy has a convenient annotation for stylesheet headers.
Example: Using the @Stylesheet
Annotation
2.6.9.2. JAXB and JSON Provider 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy allows you to marshal JAXB annotated POJOs to and from JSON using the JSON provider. This provider wraps the Jackson JSON library to accomplish this task. It has a Java Beans based model and APIs similar to JAXB.
While Jackson already includes JAX-RS integration, it was expanded by RESTEasy. To include it in your project, you need to update the Maven dependencies.
Maven Dependencies for Jackson
The default JSON provider for RESTEasy is Jackson2. Previous versions of JBoss EAP included the Jackson1 JSON provider. For more details on migrating your existing applications from the Jackson1 provider, see the JBoss EAP Migration Guide. If you still want to use the Jackson1 provider, you have to explicitly update the Maven dependencies to obtain it.
The default JSON provider for RESTEasy in previous versions of JBoss EAP was Jettison, but is now deprecated in JBoss EAP 7. For more details, see the JBoss EAP Migration Guide.
Example JSON Provider
2.6.9.2.1. Jackson Module Support for Java 8 링크 복사링크가 클립보드에 복사되었습니다!
This section provides the Maven dependencies and shows how to register the Jackson modules needed to support Java 8 features, when the core Jackson modules do not require Java 8 runtime environment. These Jackson modules include:
- Java 8 data types
- Java 8 date/time
Add the following Maven dependencies:
You can find and register all the modules using findAndRegisterModules()
or ObjectMapper.registerModule()
, as shown in the examples below:
ObjectMapper mapper = new ObjectMapper(); mapper.findAndRegisterModules();
ObjectMapper mapper = new ObjectMapper();
mapper.findAndRegisterModules();
ObjectMapper mapper = new ObjectMapper() .registerModule(new ParameterNamesModule()) .registerModule(new Jdk8Module()) .registerModule(new JavaTimeModule());
ObjectMapper mapper = new ObjectMapper()
.registerModule(new ParameterNamesModule())
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule());
Example: Duration Data Type
Example: Optional Data Type
You must use the custom implementation of the ContextResolver
in order to use these Jackson modules in RESTEasy.
2.6.9.2.2. Switching the Default Jackson Provider 링크 복사링크가 클립보드에 복사되었습니다!
JBoss EAP 7 includes Jackson 2.6.x or greater and resteasy-jackson2-provider
is now the default Jackson provider.
To switch to the default resteasy-jackson-provider
that was included in the previous release of JBoss EAP, exclude the new provider and add a dependency for the previous provider in the jboss-deployment-structure.xml
application deployment descriptor file.
2.6.10. Creating JAXB Decorators 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy’s JAXB providers have a pluggable way to decorate Marshaller and Unmarshaller instances. You can create an annotation that can trigger either a Marshaller or Unmarshaller instance, which can be used to decorate methods.
Create a JAXB Decorator with RESTEasy
Create the Processor class.
-
Create a class that implements
DecoratorProcessor<Target, Annotation>
. The target is either the JAXB Marshaller or Unmarshaller class. The annotation is created in step two. -
Annotate the class with
@DecorateTypes
, and declare the MIME types the decorator should decorate. Set properties or values within the decorate function.
Example: Processor Class
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
-
Create a class that implements
Create the annotation.
-
Create a custom interface that is annotated with the
@Decorator
annotation. Declare the processor and target for the
@Decorator
annotation. The processor is created in step one. The target is either the JAXBMarshaller
orUnmarshaller
class.Example: Custom Interface with
@Decorator
AnnotationCopy to Clipboard Copied! Toggle word wrap Toggle overflow
-
Create a custom interface that is annotated with the
- Add the annotation created in step two to a function so that either the input or output is decorated when it is marshaled.
You have now created a JAXB decorator, which can be applied within a JAX-RS web service.
2.6.11. Multipart Providers in JAX-RS 링크 복사링크가 클립보드에 복사되었습니다!
The multipart MIME format is used to pass lists of content bodies embedded in one message. One example of a multipart MIME format is the multipart/form-data
MIME type. This is often found in web application HTML form documents and is generally used to upload files. The form-data
format in this MIME type is the same as other multipart formats, except that each inlined piece of content has a name associated with it.
RESTEasy allows for the multipart/form-data
and multipart/*
MIME types. RESTEasy also provides a custom API for reading and writing multipart types as well as marshalling arbitrary List
(for any multipart type) and Map
(multipart/form-data only) objects.
There are a lot of frameworks doing multipart parsing automatically with the help of filters and interceptors, such as org.jboss.seam.web.MultipartFilter
in Seam or org.springframework.web.multipart.MultipartResolver
in Spring. However, the incoming multipart request stream can be parsed only once. RESTEasy users working with multipart should make sure that nothing parses the stream before RESTEasy gets it.
2.6.11.1. Input with Multipart Data 링크 복사링크가 클립보드에 복사되었습니다!
When writing a JAX-RS service, RESTEasy provides the org.jboss.resteasy.plugins.providers.multipart.MultipartInput
interface to allow you to read in any multipart MIME type.
MultipartInput
is a simple interface that allows you to get access to each part of the multipart message. Each part is represented by an InputPart
interface, and each part has a set of headers associated with it. You can unmarshal the part by calling one of the getBody()
methods. The genericType
parameter can be null
, but the type
parameter must be set. RESTEasy will find a MessageBodyReader
based on the media type of the part as well as the type information you pass in.
2.6.11.1.1. Input with multipart/mixed 링크 복사링크가 클립보드에 복사되었습니다!
Example: Unmarshalling Parts
The above example assumes the Customer
class is annotated with JAXB.
Sometimes you may want to unmarshal a body part that is sensitive to generic type metadata. In this case you can use the org.jboss.resteasy.util.GenericType
class.
Example: Unmarshalling a Type Sensitive to Generic Type Metadata
Use of GenericType
is required because it is the only way to obtain generic type information at runtime.
2.6.11.1.2. Input with multipart/mixed and java.util.List 링크 복사링크가 클립보드에 복사되었습니다!
If the body parts are uniform, you do not have to manually unmarshal each and every part. You can just provide a java.util.List
as your input parameter. It must have the type it is unmarshalling with the generic parameter of the List
type declaration.
Example: Unmarshalling a List
of Customers
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.1.3. Input with multipart/form-data 링크 복사링크가 클립보드에 복사되었습니다!
When writing a JAX-RS service, RESTEasy provides an interface that allows you to read in multipart/form-data
MIME type. multipart/form-data
is often found in web application HTML form documents and is generally used to upload files. The form-data
format is the same as other multipart formats, except that each inlined piece of content has a name associated with it. The interface used for form-data input is org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataInput
.
Example: MultipartFormDataInput Interface
It works in much the same way as MultipartInput
described earlier.
2.6.11.1.4. java.util.Map with multipart/form-data 링크 복사링크가 클립보드에 복사되었습니다!
With form-data, if the body parts are uniform, you do not have to manually unmarshal each and every part. You can just provide a java.util.Map
as your input parameter. It must have the type it is unmarshalling with the generic parameter of the List
type declaration.
Example: Unmarshalling a Map
of Customer
objects
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.2. Output with Multipart Data 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy provides a simple API to output multipart data.
To output multipart data, you need to create a MultipartOutput
object and call the addPart()
method. RESTEasy will automatically find a MessageBodyWriter
to marshal your entity objects. Similar to MultipartInput
, sometimes you might have marshalling that is sensitive to generic type metadata. In that case, use the GenericType
. Usually, passing in an object and its MediaType
should be enough.
Example: Returning a multipart/mixed
Format
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.2.1. Multipart Output with java.util.List 링크 복사링크가 클립보드에 복사되었습니다!
If the body parts are uniform, you do not have to manually marshal each and every part or even use a MultipartOutput
object. You can provide a java.util.List
which must have the generic type it is marshalling with the generic parameter of the List
type declaration. You must also annotate the method with the @PartType
annotation to specify the media type of each part.
Example: Returning a List
of Customer
Objects
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.2.2. Output with multipart/form-data 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy provides a simple API to output multipart/form-data
.
To output multipart/form-data
, you must create a MultipartFormDataOutput
object and call the addFormData()
method. RESTEasy will automatically find a MessageBodyWriter
to marshal your entity objects. Similar to MultipartInput
, sometimes you might have marshalling that is sensitive to generic type metadata. In that case, use the GenericType
. Usually, passing in an object and its MediaType
should be enough.
Example: Returning multipart/form-data
Format
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.2.3. Multipart FormData Output with java.util.Map 링크 복사링크가 클립보드에 복사되었습니다!
If the body parts are uniform, you do not have to manually marshal every part or use a MultipartFormDataOutput
object. You can just provide a java.util.Map
which must have the generic type it is marshalling with the generic parameter of the Map
type declaration. You must also annotate the method with the @PartType
annotation to specify the media type of each part.
Example: Returning a Map
of Customer
Objects
The above example assumes the Customer
class is annotated with JAXB.
2.6.11.3. Mapping Multipart Forms to POJOs 링크 복사링크가 클립보드에 복사되었습니다!
If you have an exact knowledge of your multipart/form-data packets, you can map them to and from a POJO class. This is accomplished using the org.jboss.resteasy.annotations.providers.multipart.MultipartForm
annotation (@MultipartForm
) and the JAX-RS @FormParam
annotation. To do so, you need to define a POJO with at least a default constructor and annotate its fields and/or properties with @FormParams
. These @FormParams
must also be annotated with org.jboss.resteasy.annotations.providers.multipart.PartType
(@PartType
) if you are creating output.
Example: Mapping Multipart Forms to a POJO
After defining your POJO class you can then use it to represent multipart/form-data
.
Example: Submit CustomerProblemForm
The @MultipartForm
annotation tells RESTEasy that the object has @FormParam
and that it should be marshaled from that. You can also use the same object to receive multipart data.
Example: Receive CustomerProblemForm
2.6.11.4. XML-binary Optimized Packaging (XOP) 링크 복사링크가 클립보드에 복사되었습니다!
If you have a JAXB annotated POJO that also holds some binary content, you may choose to send it in such a way that the binary does not need to be encoded in any way such as base64 or hex. This is accomplished using XOP and results in faster transport while still using the convenient POJO.
RESTEasy allows for XOP messages packaged as multipart/related
.
To configure XOP, you first need a JAXB annotated POJO.
Example: JAXB POJO
@XmlMimeType tells JAXB the mime type of the binary content. This is not required to do XOP packaging but it is recommended to be set if you know the exact type.
In the above POJO myBinary
and myDataHandler
will be processed as binary attachments while the whole XOP object will be sent as XML. In place of the binaries, only their references will be generated. javax.activation.DataHandler
is the most general supported type. If you need a java.io.InputStream
or a javax.activation.DataSource
, you need to use the DataHandler
. java.awt.Image
and javax.xml.transform.SourceSome
are available as well.
Example: Client Sending Binary Content with XOP
The above example assumes the Customer
class is annotated with JAXB.
The @Consumes(MultipartConstants.MULTIPART_RELATED)
is used to tell RESTEasy that you want to send multipart/related
packages, which is the container format that holds the XOP message. @XopWithMultipartRelated
is used to tell RESTEasy that you want to make XOP messages.
Example: RESTEasy Server for Receiving XOP
@Consumes(MultipartConstants.MULTIPART_RELATED)
is used to tell RESTEasy that you want to read multipart/related
packages. @XopWithMultipartRelated
is used to tell RESTEasy that you want to read XOP messages. You can configure a RESTEasy server to produce XOP values in a similar way by adding a @Produces
annotation and returning the appropriate type.
2.6.11.5. Overwriting the Default Fallback Content Type for Multipart Messages 링크 복사링크가 클립보드에 복사되었습니다!
By default, if no Content-Type
header is present in a part, text/plain; charset=us-ascii
is used as a fallback. This is defined by the MIME RFC. However some web clients, such as many browsers, may send Content-Type
headers for the file parts, but not for all fields in a multipart/form-data
request. This can cause character encoding and unmarshalling errors on the server side. The PreProcessInterceptor
infrastructure of RESTEasy can be used to correct this issue. You can use it to define another, non-RFC compliant fallback value, dynamically per request.
Example: Setting * / *; charset=UTF-8
as the Default Fallback
2.6.11.6. Overwriting the Content Type for Multipart Messages 링크 복사링크가 클립보드에 복사되었습니다!
Using an interceptor and the InputPart.DEFAULT_CONTENT_TYPE_PROPERTY attribute
allows you to set a default Content-Type
. You can also override the Content-Type
in any input part by calling org.jboss.resteasy.plugins.providers.multipart.InputPart.setMediaType()
.
Example: Overriding the Content-Type
2.6.11.7. Overwriting the Default Fallback charset for Multipart Messages 링크 복사링크가 클립보드에 복사되었습니다!
In some cases, part of a multipart message may have a Content-Type
header with no charset
parameter. If the InputPart.DEFAULT_CONTENT_TYPE_PROPERTY
property is set and the value has a charset
parameter, that value will be appended to an existing Content-Type
header that has no charset
parameter.
You can also specify a default charset
using the constant InputPart.DEFAULT_CHARSET_PROPERTY
(resteasy.provider.multipart.inputpart.defaultCharset
).
Example: Specifying a Default charset
If both InputPart.DEFAULT_CONTENT_TYPE_PROPERTY
and InputPart.DEFAULT_CHARSET_PROPERTY
are set, then the value of InputPart.DEFAULT_CHARSET_PROPERTY
will override any charset in the value of InputPart.DEFAULT_CONTENT_TYPE_PROPERTY
.
2.6.11.8. Send Multipart Entity with RESTEasy Client 링크 복사링크가 클립보드에 복사되었습니다!
In addition to configuring multipart providers, you can also configure the RESTEasy client to send multipart data.
Using RESTEasy Client Classes
To use RESTEasy client classes in your application, you must add the Maven dependencies to your project’s POM file.
Example: Maven Dependencies
Sending Multipart Data Using the RESTEasy Client
To send multipart data, you first need to configure a RESTEasy Client and construct a org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput
object to contain your multipart data. You can then use the client to send that MultipartFormDataOutput
object as a javax.ws.rs.core.GenericEntity
.
Example: RESTEasy Client
2.6.12. RESTEasy Atom Support 링크 복사링크가 클립보드에 복사되었습니다!
The RESTEasy Atom API and Provider is a simple object model that RESTEasy defines to represent Atom. The main classes for the API are in the org.jboss.resteasy.plugins.providers.atom
package. RESTEasy uses JAXB to marshal and unmarshal the API. The provider is JAXB based, and is not limited to sending Atom objects using XML. All JAXB providers that RESTEasy has can be reused by the Atom API and provider, including JSON.
2.6.12.1. Using JAXB with Atom Provider 링크 복사링크가 클립보드에 복사되었습니다!
The org.jboss.resteasy.plugins.providers.atom.Content
class allows you to unmarshal and marshal JAXB annotated objects that are the body of the content.
Example: Entry with a Customer
The Content.setJAXBObject()
method lets you specify the content object you send to JAXB to marshal appropriately. If you are using a different base format other than XML, that is application/atom+json
, the attached JAXB object is marshalled in the same format. If you have an Atom document as input, you can also extract JAXB objects from Content
using the Content.getJAXBObject(Class clazz)
method.
Example: Atom Document Extracting a Customer Object
2.6.13. YAML Provider 링크 복사링크가 클립보드에 복사되었습니다!
The resteasy-yaml-provider
module is not supported. Its use is not recommended due to a security issue in the SnakeYAML
library used by RESTEasy for unmarshalling.
RESTEasy comes with built in support for YAML using the SnakeYAML
library.
In releases prior to JBoss EAP 7.1, the YAML provider setting was enabled by default and you only needed to configure the Maven dependencies for YAML to use it in your application. This has changed in JBoss EAP 7.1. The YAML provider is now disabled by default and must be explicitly enabled in the application.
Enable the YAML Provider
To enable the YAML provider in your application, follow these steps:
-
Create or update a file named
javax.ws.rs.ext.Providers
. Add the following content to the file.
org.jboss.resteasy.plugins.providers.YamlProvider
org.jboss.resteasy.plugins.providers.YamlProvider
Copy to Clipboard Copied! Toggle word wrap Toggle overflow -
Place the file in the
META-INF/services/
folder of your WAR or JAR file.
YAML Provider Maven Dependencies
To use the YAML provider in your application, you must add the snakeyaml
JAR dependencies to the project POM file of your application.
Example: Maven Dependencies for YAML
YAML Provider Code Example
The YAML provider recognizes three mime types:
- text/x-yaml
- text/yaml
- application/x-yaml
The following is an example of how to use YAML in a resource method.
Example: Resource Producing YAML
2.7. Using the JSON API for JSON Processing (JSON-P) 링크 복사링크가 클립보드에 복사되었습니다!
The JSON API for JSON Processing (JSON-P) is a part of the Java EE 7 specification and is defined in JSR 353. JSON-P defines an API to process JSON. JBoss EAP has support for javax.json.JsonObject
, javax.json.JsonArray
, and javax.json.JsonStructure
as request or response entities.
The JSON API for JSON Processing (JSON-P) is different from JSON with Padding (JSONP).
JSON-P will not conflict with Jackson if they are on the same classpath.
To create a JsonObject
, use the JsonObjectBuilder
by calling Json.createObjectBuilder()
and building the JSON object.
Example: Create javax.json.JsonObject
JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();
JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();
Example: Corresponding JSON for javax.json.JsonObject
{ "name":"Bill" }
{
"name":"Bill"
}
To create a JsonArray
, use the JsonArrayBuilder
by calling Json.createArrayBuilder()
and building the JSON array.
Example: Create javax.json.JsonArray
JsonArray array = Json.createArrayBuilder() .add(Json.createObjectBuilder().add("name", "Bill").build()) .add(Json.createObjectBuilder().add("name", "Monica").build()).build();
JsonArray array =
Json.createArrayBuilder()
.add(Json.createObjectBuilder().add("name", "Bill").build())
.add(Json.createObjectBuilder().add("name", "Monica").build()).build();
Example: Corresponding JSON for javax.json.JsonArray
JsonStructure
is a parent class of JsonObject
and JsonArray
.
Example: Create javax.json.JsonStructure
You can use JsonObject
, JsonArray
, and JsonStructure
directly in JAX-RS resources.
Example: JAX-RS Resources with JSON-P
You can also use JSON-P from a client to send JSON.
Example: Client Using JSON-P
WebTarget target = client.target(...); JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build(); JsonObject newObj = target.request().post(Entity.json(obj), JsonObject.class);
WebTarget target = client.target(...);
JsonObject obj = Json.createObjectBuilder().add("name", "Bill").build();
JsonObject newObj = target.request().post(Entity.json(obj), JsonObject.class);
2.8. RESTEasy/EJB Integration 링크 복사링크가 클립보드에 복사되었습니다!
To integrate RESTEasy with EJB, add JAX-RS annotations to the EJB classes that you want to expose as JAX-RS endpoints. You can also apply the annotations on the bean’s business interface. There are two ways to activate the beans as endpoints:
-
Using the
web.xml
file. -
Using
javax.ws.rs.core.Application
.
To make an EJB function as a JAX-RS resource, annotate a stateless session bean’s @Remote
or @Local
interface with JAX-RS annotations:
Note that the Library
interface is referenced by fully qualified name, whereas LibraryBean
is referenced only by the simple class name.
Then, manually register the EJB with RESTEasy using the resteasy.jndi.resources
context parameter in the RESTEasy web.xml
file:
You can also specify multiple JNDI names of EJBs, separated by commas, for the resteasy.jndi.resources
context parameter.
An alternate Java EE-standard way to activate EJBs as RESTEasy endpoints is by using javax.ws.rs.core.Application
. This is achieved by including the EJB implementation class into the set returned by the application’s getClasses()
method. This approach does not need anything to be specified in the web.xml
file.
See the kitchensink
, helloworld-html5
, and managed-executor-service
quickstarts that ship with JBoss EAP for working examples that demonstrate RESTEasy integration with EJBs.
2.9. Spring Integration 링크 복사링크가 클립보드에 복사되었습니다!
Your application must have an existing JAX-WS service and client configuration.
RESTEasy integrates with Spring 4.2.x.
Maven users must use the resteasy-spring
artifact. Alternatively, the JAR is available as a module in JBoss EAP.
RESTEasy comes with its own Spring ContextLoaderListener
that registers a RESTEasy specific BeanPostProcessor
that processes JAX-RS annotations when a bean is created by a BeanFactory
. This means that RESTEasy automatically scans for @Provider
and JAX-RS resource annotations on your bean class and registers them as JAX-RS resources.
Add the following to your web.xml
file to enable the RESTEasy/Spring integration functionality:
The SpringContextLoaderListener
must be declared after ResteasyBootstrap
as it uses ServletContext
attributes initialized by it.
See the spring-resteasy
quickstart that ships with JBoss EAP for a working example of a web application that demonstrates RESTEasy integration with Spring.
2.10. CDI Integration 링크 복사링크가 클립보드에 복사되었습니다!
Integration between RESTEasy and CDI is provided by the resteasy-cdi
module.
Both the JAX-RS and CDI specifications introduce their own component models. Every class placed in a CDI archive, which fulfills a set of basic constraints, is implicitly a CDI bean. Explicit declaration of your Java class with @Path
or @Provider
is required for it to become a JAX-RS component. Without the integration code, annotating a class suitable for being a CDI bean with JAX-RS annotations gives a faulty result and the JAX-RS component is not managed by the CDI. The resteasy-cdi
module is a bridge that allows RESTEasy to work with class instances obtained from the CDI container.
During a web service invocation, the resteasy-cdi
module asks the CDI container for the managed instance of a JAX-RS component. Then, this instance is passed to RESTEasy. If a managed instance is not available for some reason, such as the class being placed in a JAR file that is not a bean deployment archive, RESTEasy falls back to instantiating the class itself.
As a result, CDI services like injection, lifecycle management, events, decoration, and interceptor bindings can be used in JAX-RS components.
2.10.1. Default Scope 링크 복사링크가 클립보드에 복사되었습니다!
A CDI bean that does not explicitly define a scope is @Dependent
scoped by default. This pseudo-scope means that the bean adapts to the lifecycle of the bean that it is injected into. Normal scopes, including request, session, and application, are more suitable for JAX-RS components as they designate the component’s lifecycle boundaries explicitly. Therefore, the resteasy-cdi
module alters the default scoping in the following way:
- If a JAX-RS root resource does not define a scope explicitly, it is bound to the request scope.
-
If a JAX-RS provider or
javax.ws.rs.Application
subclass does not define a scope explicitly, it is bound to the application scope.
Since the scope of all beans that do not declare a scope is modified by the resteasy-cdi
module, this affects session beans as well. As a result, a conflict occurs if the scope of a stateless session bean or singleton is changed automatically as the specification prohibits these components to be @RequestScoped
. Therefore, you need to explicitly define a scope when using stateless session beans or singletons. This requirement is likely to be removed in future releases.
The resteasy-cdi
module is bundled with JBoss EAP. Therefore, there is no need to download the module separately or add any additional configuration. See the kitchensink
quickstart that ships with JBoss EAP for a working example of using CDI beans with a JAX-RS resource.
2.11. RESTEasy Filters and Interceptors 링크 복사링크가 클립보드에 복사되었습니다!
JAX-RS 2.0 has two different concepts for interceptions: filters and interceptors. Filters are mainly used to modify or process incoming and outgoing request headers or response headers. They execute before and after request and response processing.
2.11.1. Server-side Filters 링크 복사링크가 클립보드에 복사되었습니다!
On the server side, you have two different types of filters: ContainerRequestFilters
and ContainerResponseFilters
. ContainerRequestFilters
run before your JAX-RS resource method is invoked. ContainerResponseFilters
run after your JAX-RS resource method is invoked.
In addition, there are two types of ContainerRequestFilters
: pre-matching and post-matching. Pre-matching ContainerRequestFilters
are designated with the @PreMatching
annotation and execute before the JAX-RS resource method is matched with the incoming HTTP request. Post-matching ContainerRequestFilters
are designated with the @PostMatching
annotation and execute after the JAX-RS resource method is matched with the incoming HTTP request.
Pre-matching filters often are used to modify request attributes to change how it matches to a specific resource method, for example to strip .xml
and add an Accept
header. ContainerRequestFilters
can abort the request by calling ContainerRequestContext.abortWith(Response)
. For example, a filter might want to abort if it implements a custom authentication protocol.
After the resource class method is executed, JAX-RS runs all ContainerResponseFilters
. These filters allow you to modify the outgoing response before it is marshalled and sent to the client.
Example: Request Filter
Example: Response Filter
2.11.2. Client-side Filters 링크 복사링크가 클립보드에 복사되었습니다!
More information on client-side filters can be found in the JAX-RS 2.0 Client API section of this guide.
2.11.3. RESTEasy Interceptors 링크 복사링크가 클립보드에 복사되었습니다!
2.11.3.1. Intercept JAX-RS Invocations 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy can intercept JAX-RS invocations and route them through listener-like objects called interceptors.
While filters modify request or response headers, interceptors deal with message bodies. Interceptors are executed in the same call stack as their corresponding reader or writer. ReaderInterceptors
wrap around the execution of MessageBodyReaders
. WriterInterceptors
wrap around the execution of MessageBodyWriters
. They can be used to implement a specific content-encoding. They can be used to generate digital signatures or to post or pre-process a Java object model before or after it is marshalled.
ReaderInterceptors
and WriterInterceptors
can be used on either the server or client side. They are annotated with @Provider
, as well as either @ServerInterceptor
or @ClientInterceptor
so that RESTEasy knows whether or not to add them to the interceptor list.
These interceptors wrap around the invocation of MessageBodyReader.readFrom()
or MessageBodyWriter.writeTo()
. They can be used to wrap the Output
or Input
streams.
Example: Interceptor
The interceptors and the MessageBodyReader
or Writer
are invoked in one big Java call stack. ReaderInterceptorContext.proceed()
or WriterInterceptorContext.proceed()
are called in order to go to the next interceptor or, if there are no more interceptors to invoke, the readFrom()
or writeTo()
method of the MessageBodyReader
or MessageBodyWriter
. This wrapping allows objects to be modified before they get to the Reader
or Writer
, and then cleaned up after proceed()
returns.
The example below is a server-side interceptor that adds a header value to the response.
2.11.3.2. Registering an Interceptor 링크 복사링크가 클립보드에 복사되었습니다!
To register a RESTEasy JAX-RS interceptor in an application, list it in the web.xml
file under the resteasy.providers
parameter in the context-param
element, or return it as a class or as an object in the Application.getClasses()
or Application.getSingletons()
method.
<context-param> <param-name>resteasy.providers</param-name> <param-value>my.app.CustomInterceptor</paramvalue> </context-param>
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>my.app.CustomInterceptor</paramvalue>
</context-param>
2.11.4. GZIP Compression and Decompression 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy supports GZIP compression and decompression. To support GZIP decompression, the client framework or a JAX-RS service automatically decompresses a message body with a Content-Encoding
of gzip
, and it can automatically set the Accept-Encoding
header to gzip, deflate
so that you do not have to set this header manually. To support GZIP compression, RESTEasy compresses the outgoing message if the client framework is sending a request or if the server is sending a response with the Content-Encoding
header set to gzip
. You can use the @org.jboss.resteasy.annotation.GZIP
annotation to set the Content-Encoding
header.
The following example tags the outgoing message body order
to be gzip compressed.
Example: GZIP Compression
Example: GZIP Compression Tagging Server Responses
2.11.4.1. Configuring GZIP Compression and Decompression 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy disables GZIP compression and decompression by default in order to prevent decompression of an entity that might be huge in size but has been compressed by an attacker and sent to the server.
There are three interceptors that are relevant to GZIP compression and decompression:
-
org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor
: If theContent-Encoding
header is present and has the valuegzip
,GZIPDecodingInterceptor
installs anInputStream
that decompresses the message body. -
org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor
: If theContent-Encoding
header is present and has the valuegzip
,GZIPEncodingInterceptor
installs anOutputStream
that compresses the message body. org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter
: If theAccept-Encoding
header does not exist,AcceptEncodingGZIPFilter
addsAccept-Encoding
header with the valuegzip, deflate
. If theAccept-Encoding
header exists but does not containgzip
,AcceptEncodingGZIPFilter
interceptor appends the value, gzip
.NoteEnabling GZIP compression or decompression does not depend on the presence of the
AcceptEncodingGZIPFilter
interceptor.
Enabling GZIP decompression sets an upper limit on the number of bytes the GZIPDecodingInterceptor
can extract from the compressed message body. The default limit is 10,000,000
.
2.11.4.2. Server-side GZIP Configuration 링크 복사링크가 클립보드에 복사되었습니다!
You can enable the interceptors by including their class names in the javax.ws.rs.ext.Providers
file on the class path. The upper limit on deflated files is set using the web application context parameter resteasy.gzip.max.input
. If this limit is exceeded on the server side, GZIPDecodingInterceptor
returns a response with status 413 - Request Entity Too Large
and a message specifying the upper limit.
2.11.4.2.1. Client-side GZIP Configuration 링크 복사링크가 클립보드에 복사되었습니다!
You can enable the GZIP interceptors by registering them with, for example, a Client
or WebTarget
. For example:
Client client = new ResteasyClientBuilder() // Activate gzip compression on client: .register(AcceptEncodingGZIPFilter.class) .register(GZIPDecodingInterceptor.class) .register(GZIPEncodingInterceptor.class) .build();
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(GZIPDecodingInterceptor.class)
.register(GZIPEncodingInterceptor.class)
.build();
You can configure the upper limit on deflated files by creating an instance of GZIPDecodingInterceptor
with a specific value:
Client client = new ResteasyClientBuilder() // Activate gzip compression on client: .register(AcceptEncodingGZIPFilter.class) .register(new GZIPDecodingInterceptor(256)) .register(GZIPEncodingInterceptor.class) .build();
Client client = new ResteasyClientBuilder() // Activate gzip compression on client:
.register(AcceptEncodingGZIPFilter.class)
.register(new GZIPDecodingInterceptor(256))
.register(GZIPEncodingInterceptor.class)
.build();
If the upper limit is exceeded on the client side, GZIPDecodingInterceptor
throws a ProcessingException
with a message specifying the upper limit.
2.11.5. Per-Resource Method Filters and Interceptors 링크 복사링크가 클립보드에 복사되었습니다!
Sometimes you want a filter or interceptor to only run for a specific resource method. You can do this in two different ways:
Implement the DynamicFeature
Interface
The DynamicFeature
interface includes a callback method, configure(ResourceInfo resourceInfo, FeatureContext context)
, which is invoked for each and every deployed JAX-RS method. The ResourceInfo
parameter contains information about the current JAX-RS method being deployed. FeatureContext
is an extension of the Configurable
interface. You can use the register()
method of this parameter to bind the filters and interceptors that you want to assign to this method.
Example: Using the DynamicFeature Interface
In the example above, the provider that you register using AnimalTypeFeature
must implement one of the interfaces. This example registers the provider AnimalFilter
that must implement one of the following interfaces: ContainerRequestFilter
, ContainerResponseFilter
, ReaderInterceptor
, WriterInterceptor
, or Feature
. In this case AnimalFilter
will be applied to all resource methods annotated with GET annotation. See DynamicFeature Documentation for details.
Use the @NameBinding Annotation
@NameBinding
works a lot like CDI interceptors. You annotate a custom annotation with @NameBinding
and then apply that custom annotation to your filter and resource method.
Example: Using @NameBinding
See NameBinding Documentation for details.
2.11.6. Ordering 링크 복사링크가 클립보드에 복사되었습니다!
Ordering is accomplished by using the @Priority
annotation on your filter or interceptor class.
2.11.7. Exception Handling with Filters and Interceptors 링크 복사링크가 클립보드에 복사되었습니다!
Exceptions associated with filters or interceptors can occur on either the client side or the server side. On the client side, there are two types of exceptions you will have to handle: javax.ws.rs.client.ProcessingException
and javax.ws.rs.client.ResponseProcessingException
. A javax.ws.rs.client.ProcessingException
will be thrown on the client side if there was an error before a request is sent to the server. A javax.ws.rs.client.ResponseProcessingException
will be thrown on the client side if there was an error in processing the response received by the client from the server.
On the server side, exceptions thrown by filters or interceptors are handled in the same way as other exceptions thrown from JAX-RS methods, which tries to find an ExceptionMapper
for the exception being thrown. More details on how exceptions are handled in JAX-RS methods can be found in the Exception Handling section.
2.12. Logging RESTEasy Providers and Interceptors 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy logs the used providers and interceptors in the DEBUG
level of logging. You can use the following management CLI commands to enable all the log levels related to RESTEasy:
2.13. Exception Handling 링크 복사링크가 클립보드에 복사되었습니다!
2.13.1. Creating an Exception Mapper 링크 복사링크가 클립보드에 복사되었습니다!
Exception mappers are custom components provided by applications that catch thrown exceptions and write specific HTTP responses.
When you create an exception mapper, you create a class that is annotated with the @Provider
annotation and implements the ExceptionMapper
interface.
An example exception mapper is provided below:
To register an exception mapper, list it in the web.xml
file, under the resteasy.providers
context-param
, or register it programmatically through the ResteasyProviderFactory
class.
2.13.2. Managing Internally Thrown Exceptions 링크 복사링크가 클립보드에 복사되었습니다!
Exception | HTTP Code | Description |
---|---|---|
BadRequestException | 400 | Bad Request. The request was not formatted correctly, or there was a problem processing the request input. |
UnauthorizedException | 401 | Unauthorized. Security exception thrown if you are using RESTEasy’s annotation-based role-based security. |
InternalServerErrorException | 500 | Internal Server Error. |
MethodNotAllowedException | 405 | There is no JAX-RS method for the resource to handle the invoked HTTP operation. |
NotAcceptableException | 406 | There is no JAX-RS method that can produce the media types listed in the Accept header. |
NotFoundException | 404 | There is no JAX-RS method that serves the request path/resource. |
ReaderException | 400 | All exceptions thrown from MessageBodyReaders are wrapped within this exception. If there is no ExceptionMapper for the wrapped exception, or if the exception is not a WebApplicationException, then by default, RESTEasy returns a 400 code. |
WriterException | 500 | All exceptions thrown from MessageBodyWriters are wrapped within this exception. If there is no ExceptionMapper for the wrapped exception, or if the exception is not a WebApplicationException, then by default, RESTEasy returns a 400 code. |
JAXBUnmarshalException | 400 | The JAXB providers (XML and Jackson) throw this exception on reads which might wrap JAXBExceptions. This class extends ReaderException. |
JAXBMarshalException | 500 | The JAXB providers (XML and Jackson) throw this exception on writes which might wrap JAXBExceptions. This class extends WriterException. |
ApplicationException | N/A | Wraps all exceptions thrown from application code, and it functions in the same way as InvocationTargetException. If there is an ExceptionMapper for wrapped exception, then that is used to handle the request. |
Failure | N/A | Internal RESTEasy error. Not logged. |
LoggableFailure | N/A | Internal RESTEasy error. Logged. |
DefaultOptionsMethodException | N/A |
If the user invokes |
UnrecognizedPropertyExceptionHandler | 400 | RESTEasy Jackson provider throws this exception when JSON data is determined to be invalid. |
2.14. Securing JAX-RS Web Services 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy supports the @RolesAllowed
, @PermitAll
, and @DenyAll
annotations on JAX-RS methods. However, you must enable role-based security in order for these annotations to be recognized.
2.14.1. Enable Role-Based Security 링크 복사링크가 클립보드에 복사되었습니다!
Follow these steps to configure the web.xml
file to enable role-based security.
Do not activate role-based security if the application uses EJBs. The EJB container will provide the functionality, instead of RESTEasy.
Enable Role-Based Security for a RESTEasy JAX-RS Web Service
-
Open the
web.xml
file for the application in a text editor. Add the following
<context-param>
to the file, within the<web-app>
tags.<context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param>
<context-param> <param-name>resteasy.role.based.security</param-name> <param-value>true</param-value> </context-param>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Declare all roles used within the RESTEasy JAX-RS WAR file, using the
<security-role>
tags.Copy to Clipboard Copied! Toggle word wrap Toggle overflow Authorize access to all URLs handled by the JAX-RS runtime for all roles.
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Define the appropriate login configuration for this application.
<login-config> <auth-method>BASIC</auth-method> <realm-name>jaxrs</realm-name> </login-config>
<login-config> <auth-method>BASIC</auth-method> <realm-name>jaxrs</realm-name> </login-config>
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Role-based security has been enabled within the application, with a set of defined roles.
Example: Role-Based Security Configuration
2.14.2. Securing JAX-RS Web Services Using Annotations 링크 복사링크가 클립보드에 복사되었습니다!
To secure JAX-RS web services using an annotation, complete the following steps.
- Enable role-based security.
Add security annotations to the JAX-RS web service. RESTEasy supports the following annotations:
@RolesAllowed
-
Defines which roles can access the method. All roles should be defined in the
web.xml
file. @PermitAll
-
Allows all roles defined in the
web.xml
file to access the method. @DenyAll
- Denies all access to the method.
Below is an example that uses the @RolesAllowed
annotation to specify that the admin
role can access the web service.
@RolesAllowed("admin") @Path("/test") public class TestService { ... }
@RolesAllowed("admin")
@Path("/test")
public class TestService {
...
}
2.14.3. Setting Programmatic Security 링크 복사링크가 클립보드에 복사되었습니다!
JAX-RS includes a programmatic API for gathering security information about a secured request. The javax.ws.rs.core.SecurityContext
interface has a method for determining the identity of the user making the secured HTTP invocation. It also has a method that allows you to check whether or not the current user belongs to a certain role:
You can access a SecurityContext
instance by injecting it into a field, setter method, or resource method parameter using the @Context
annotation.
2.15. RESTEasy Asynchronous Job Service 링크 복사링크가 클립보드에 복사되었습니다!
The RESTEasy Asynchronous Job Service is designed to add asynchronous behavior to the HTTP protocol. While HTTP is a synchronous protocol, it is aware of asynchronous invocations. The HTTP 1.1 response code 202 Accepted
means that the server has received and accepted the response for processing, but the processing has not yet been completed. The Asynchronous Job Service builds around this.
2.15.1. Enabling the Asynchronous Job Service 링크 복사링크가 클립보드에 복사되었습니다!
Enable the asynchronous job service in the web.xml
file:
<context-param> <param-name>resteasy.async.job.service.enabled</param-name> <param-value>true</param-value> </context-param>
<context-param>
<param-name>resteasy.async.job.service.enabled</param-name>
<param-value>true</param-value>
</context-param>
2.15.2. Configuring Asynchronous Jobs 링크 복사링크가 클립보드에 복사되었습니다!
This section covers examples of the query parameters for asynchronous jobs with RESTEasy.
Role based security does not work with the Asynchronous Job Service as it cannot be implemented portably. If the Asynchronous Job Service is used, application security must be done through XML declarations in the web.xml
file instead.
While GET, DELETE, and PUT methods can be invoked asynchronously, this breaks the HTTP 1.1 contract of these methods. While these invocations might not change the state of the resource if invoked more than once, they do change the state of the server as new job entries with each invocation.
The asynch
query parameter is used to run invocations in the background. A 202 Accepted
response is returned, as well as a location header with a URL pointing to where the response of the background method is located.
POST http://example.com/myservice?asynch=true
POST http://example.com/myservice?asynch=true
The example above returns a 202 Accepted
response. It also returns a location header with a URL pointing to where the response of the background method is located. An example of the location header is shown below:
HTTP/1.1 202 Accepted Location: http://example.com/asynch/jobs/3332334
HTTP/1.1 202 Accepted
Location: http://example.com/asynch/jobs/3332334
The URI will take the form of:
/asynch/jobs/{job-id}?wait={milliseconds}|nowait=true
/asynch/jobs/{job-id}?wait={milliseconds}|nowait=true
GET, POST and DELETE operations can be performed on this URL.
-
GET returns the JAX-RS resource method invoked as a response if the job was completed. If the job has not been completed, the GET returns a
202 Accepted
response code. Invoking GET does not remove the job, so it can be called multiple times. - POST does a read of the job response and removes the job if it has been completed.
- DELETE is called to manually clean up the job queue.
When the job queue is full, it evicts the earliest job from memory automatically without needing to call DELETE.
The GET and POST operations allow for the maximum wait time to be defined, using the wait
and nowait
query parameters. If the wait
parameter is not specified, the operation will default to nowait=true
, and will not wait at all if the job is not complete. The wait
parameter is defined in milliseconds.
POST http://example.com/asynch/jobs/122?wait=3000
POST http://example.com/asynch/jobs/122?wait=3000
RESTEasy supports fire and forget jobs, using the oneway
query parameter.
POST http://example.com/myservice?oneway=true
POST http://example.com/myservice?oneway=true
The example above returns a 202 Accepted
response, but no job is created.
The configuration parameters for the Asynchronous Job Service can be found in the RESTEasy Asynchronous Job Service Configuration Parameters section in the appendix.
2.16. RESTEasy JavaScript API 링크 복사링크가 클립보드에 복사되었습니다!
2.16.1. About the RESTEasy JavaScript API 링크 복사링크가 클립보드에 복사되었습니다!
RESTEasy can generate a JavaScript API that uses AJAX calls to invoke JAX-RS operations. Each JAX-RS resource class will generate a JavaScript object of the same name as the declaring class or interface. The JavaScript object contains each JAX-RS method as properties.
The following JavaScript code uses the JAX-RS API that was generated in the previous example.
var text = Foo.get({order: 'desc', 'X-Foo': 'hello', colour: 'blue', 'Foo-Cookie': 123987235444}); Foo.post({$entity: text});
var text = Foo.get({order: 'desc', 'X-Foo': 'hello', colour: 'blue', 'Foo-Cookie': 123987235444});
Foo.post({$entity: text});
Each JavaScript API method takes an optional object as single parameter where each property is a cookie, header, path, query or form parameter as identified by its name, or the API parameter properties. For details about the API parameter properties see RESTEasy Javascript API Parameters appendix.
2.16.1.1. Enable the RESTEasy JavaScript API Servlet 링크 복사링크가 클립보드에 복사되었습니다!
The RESTEasy JavaScript API is disabled by default. Follow these steps to enable it by updating the web.xml
file.
-
Open the
web.xml
file of the application in a text editor. Add the following configuration to the file, inside the
web-app
tags:Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.16.1.2. Build AJAX Queries 링크 복사링크가 클립보드에 복사되었습니다!
The RESTEasy JavaScript API can be used to manually construct requests. The following are some examples of this behavior.
Example: REST Object Used to Override RESTEasy JavaScript API Client Behavior
The REST
object contains the following read-write properties:
-
apiURL
: Set by default to the JAX-RS root URL. Used by every JavaScript client API functions when constructing the requests. -
log
: Set tofunction(string)
in order to receive RESTEasy client API logs. This is useful if you want to debug your client API and place the logs where you can see them.
Example: Class Using REST.Request() Method to Build Custom Requests