Remoting and Web Services Using Spring
Remoting and Web Services Using Spring
html
27.1 Introduction
For security reasons, browsers prohibit AJAX calls to resources residing outside the current
origin. For example, as you’re checking your bank account in one tab, you could have the
evil.com website open in another tab. The scripts from evil.com should not be able to make
AJAX requests to your bank API (e.g., withdrawing money from your account!) using your
credentials.
As of Spring Framework 4.2, CORS is supported out of the box. CORS requests (including
preflight ones with an OPTIONS method) are automatically dispatched to the various registered
HandlerMappings. They handle CORS preflight requests and intercept CORS simple and
actual requests thanks to a CorsProcessor implementation (DefaultCorsProcessor by default)
in order to add the relevant CORS response headers (like Access-Control-Allow-Origin)
based on the CORS configuration you have provided.
Since CORS requests are automatically dispatched, you do not need to change
the DispatcherServlet dispatchOptionsRequest init parameter value; using its
default value (false) is the recommended approach.
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
In the above example CORS support is enabled for both the retrieve() and the remove()
handler methods, and you can also see how you can customize the CORS configuration
using @CrossOrigin attributes.
You can even use both controller-level and method-level CORS configurations; Spring will
then combine attributes from both annotations to create merged CORS configuration.
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("http://domain2.com")
@RequestMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
27.3.1 JavaConfig
Enabling CORS for the whole application is as simple as:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
}
You can easily change any properties, as well as only apply this CORS configuration to a
specific path pattern:
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://domain2.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(false).maxAge(3600);
}
}
<mvc:cors>
<mvc:mapping path="/**" />
</mvc:cors>
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="http://domain1.com, http://domain2.com"
allowed-methods="GET, PUT"
allowed-headers="header1, header2, header3"
exposed-headers="header1, header2" allow-credentials="false"
max-age="123" />
<mvc:mapping path="/resources/**"
allowed-origins="http://domain1.com" />
</mvc:cors>
public MyCorsFilter() {
super(configurationSource());
}
You need to ensure that CorsFilter is ordered before the other filters, see this blog post
about how to configure Spring Boot accordingly.
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/remoting.html
28.1 Introduction
Spring features integration classes for remoting support using various technologies. The
remoting support eases the development of remote-enabled services, implemented by your
usual (Spring) POJOs. Currently, Spring supports the following remoting technologies:
While discussing the remoting capabilities of Spring, we’ll use the following domain model and
corresponding services:
}
public interface AccountService {
}
// the implementation doing nothing at the moment
public class AccountServiceImpl implements AccountService {
We will start exposing the service to a remote client by using RMI and talk a bit about the
drawbacks of using RMI. We’ll then continue to show an example using Hessian as the
protocol.
<bean class="org.springframework.remoting.rmi.RmiServiceExporter">
<!-- does not necessarily have to be the same name as the bean to be
exported -->
<property name="serviceName" value="AccountService"/>
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
<!-- defaults to 1099 -->
<property name="registryPort" value="1199"/>
</bean>
As you can see, we’re overriding the port for the RMI registry. Often, your application server
also maintains an RMI registry and it is wise to not interfere with that one. Furthermore, the
service name is used to bind the service under. So right now, the service will be bound at
'rmi://HOST:1199/AccountService'. We’ll use the URL later on to link in the service at
the client side.
The servicePort property has been omitted (it defaults to 0). This means that an
anonymous port will be used to communicate with the service.
To link in the service on the client, we’ll create a separate Spring container, containing the
simple object and the service linking configuration bits:
<bean class="example.SimpleObject">
<property name="accountService" ref="accountService"/>
</bean>
<bean id="accountService"
class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="serviceUrl" value="rmi://HOST:1199/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
That’s all we need to do to support the remote account service on the client. Spring will
transparently create an invoker and remotely enable the account service through the
RmiServiceExporter. At the client we’re linking it in using the RmiProxyFactoryBean.
<servlet>
<servlet-name>remoting</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-
class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>remoting</servlet-name>
<url-pattern>/remoting/*</url-pattern>
</servlet-mapping>
You’re probably familiar with Spring’s DispatcherServlet principles and if so, you know that
now you’ll have to create a Spring container configuration resource named 'remoting-
servlet.xml' (after the name of your servlet) in the 'WEB-INF' directory. The application
context will be used in the next section.
<bean name="/AccountService"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
Now we’re ready to link in the service at the client. No explicit handler mapping is specified,
mapping request URLs onto services, so BeanNameUrlHandlerMapping will be used: Hence,
the service will be exported at the URL indicated through its bean name within the containing
DispatcherServlet’s mapping (as defined above):
’http://HOST:8080/remoting/AccountService'.
<bean name="accountExporter"
class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
In the latter case, define a corresponding servlet for this exporter in 'web.xml', with the
same end result: The exporter getting mapped to the request path
/remoting/AccountService. Note that the servlet name needs to match the bean name of
the target exporter.
<servlet>
<servlet-name>accountExporter</servlet-name>
<servlet-
class>org.springframework.web.context.support.HttpRequestHandlerServlet</servl
et-class>
</servlet>
<servlet-mapping>
<servlet-name>accountExporter</servlet-name>
<url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>
<bean class="example.SimpleObject">
<property name="accountService" ref="accountService"/>
</bean>
<bean id="accountService"
class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
<property name="serviceUrl"
value="http://remotehost:8080/remoting/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors" ref="authorizationInterceptor"/>
</bean>
<bean id="authorizationInterceptor"
class="org.springframework.web.servlet.handler.UserRoleAuthorizationIntercepto
r">
<property name="authorizedRoles" value="administrator,operator"/>
</bean>
Of course, this example doesn’t show a flexible kind of security infrastructure. For
more options as far as security is concerned, have a look at the Spring Security
project at http://projects.spring.io/spring-security/.
Under the hood, Spring uses either the standard facilities provided by the JDK or Apache
HttpComponents to perform HTTP calls. Use the latter if you need more advanced and
easier-to-use functionality. Refer to hc.apache.org/httpcomponents-client-ga/ for more
information.
<bean name="/AccountService"
class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
In addition, define a corresponding servlet for this exporter in 'web.xml', with the servlet
name matching the bean name of the target exporter:
<servlet>
<servlet-name>accountExporter</servlet-name>
<servlet-
class>org.springframework.web.context.support.HttpRequestHandlerServlet</servl
et-class>
</servlet>
<servlet-mapping>
<servlet-name>accountExporter</servlet-name>
<url-pattern>/remoting/AccountService</url-pattern>
</servlet-mapping>
If you are running outside of a servlet container and are using Oracle’s Java 6, then you can
use the built-in HTTP server implementation. You can configure the
SimpleHttpServerFactoryBean together with a SimpleHttpInvokerServiceExporter as
is shown in this example:
<bean name="accountExporter"
class="org.springframework.remoting.httpinvoker.SimpleHttpInvokerServiceExport
er">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
<bean id="httpServer"
class="org.springframework.remoting.support.SimpleHttpServerFactoryBean">
<property name="contexts">
<util:map>
<entry key="/remoting/AccountService" value-
ref="accountExporter"/>
</util:map>
</property>
<property name="port" value="8080" />
</bean>
28.4.2 Linking in the service at the client
Again, linking in the service from the client much resembles the way you would do it when
using Hessian or Burlap. Using a proxy, Spring will be able to translate your calls to HTTP
POST requests to the URL pointing to the exported service.
<bean id="httpInvokerProxy"
class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
<property name="serviceUrl"
value="http://remotehost:8080/remoting/AccountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
As mentioned before, you can choose what HTTP client you want to use. By default, the
HttpInvokerProxy uses the JDK’s HTTP functionality, but you can also use the Apache
HttpComponents client by setting the httpInvokerRequestExecutor property:
<property name="httpInvokerRequestExecutor">
<bean
class="org.springframework.remoting.httpinvoker.HttpComponentsHttpInvokerReque
stExecutor"/>
</property>
In addition to stock support for JAX-WS in Spring Core, the Spring portfolio also features
Spring Web Services, a solution for contract-first, document-driven web services - highly
recommended for building modern, future-proof web services.
/**
* JAX-WS compliant AccountService implementation that simply delegates
* to the AccountService implementation in the root web application context.
*
* This wrapper class is necessary because JAX-WS requires working with
dedicated
* endpoint classes. If an existing service needs to be exported, a wrapper
that
* extends SpringBeanAutowiringSupport for simple Spring bean autowiring
(through
* the @Autowired annotation) is the simplest JAX-WS compliant way.
*
* This is the class registered with the server-side JAX-WS implementation.
* In the case of a Java EE 5 server, this would simply be defined as a
servlet
* in web.xml, with the server detecting that this is a JAX-WS endpoint and
reacting
* accordingly. The servlet name usually needs to match the specified WS
service name.
*
* The web service engine manages the lifecycle of instances of this class.
* Spring bean references will just be wired in here.
*/
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
@WebService(serviceName="AccountService")
public class AccountServiceEndpoint extends SpringBeanAutowiringSupport {
@Autowired
private AccountService biz;
@WebMethod
public void insertAccount(Account acc) {
biz.insertAccount(acc);
}
@WebMethod
public Account[] getAccounts(String name) {
return biz.getAccounts(name);
}
Our AccountServiceEndpoint needs to run in the same web application as the Spring
context to allow for access to Spring’s facilities. This is the case by default in Java EE 5
environments, using the standard contract for JAX-WS servlet endpoint deployment. See
Java EE 5 web service tutorials for details.
In this scenario, the endpoint instances are defined and managed as Spring beans
themselves; they will be registered with the JAX-WS engine but their lifecycle will be up to the
Spring application context. This means that Spring functionality like explicit dependency
injection may be applied to the endpoint instances. Of course, annotation-driven injection
through @Autowired will work as well.
<bean class="org.springframework.remoting.jaxws.SimpleJaxWsServiceExporter">
<property name="baseAddress" value="http://localhost:8080/"/>
</bean>
...
@WebService(serviceName="AccountService")
public class AccountServiceEndpoint {
@Autowired
private AccountService biz;
@WebMethod
public void insertAccount(Account acc) {
biz.insertAccount(acc);
}
@WebMethod
public List<Account> getAccounts(String name) {
return biz.getAccounts(name);
}
The difference to the standard style of exporting servlet-based endpoints is that the lifecycle
of the endpoint instances themselves will be managed by Spring here, and that there will be
only one JAX-WS servlet defined in web.xml. With the standard Java EE 5 style (as
illustrated above), you’ll have one servlet definition per service endpoint, with each endpoint
typically delegating to Spring beans (through the use of @Autowired, as shown above).
<bean id="accountWebService"
class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="example.AccountService"/>
<property name="wsdlDocumentUrl"
value="http://localhost:8888/AccountServiceEndpoint?WSDL"/>
<property name="namespaceUri" value="http://example/"/>
<property name="serviceName" value="AccountService"/>
<property name="portName" value="AccountServiceEndpointPort"/>
</bean>
Where serviceInterface is our business interface the clients will use. wsdlDocumentUrl is
the URL for the WSDL file. Spring needs this a startup time to create the JAX-WS Service.
namespaceUri corresponds to the targetNamespace in the .wsdl file. serviceName
corresponds to the service name in the .wsdl file. portName corresponds to the port name in
the .wsdl file.
Accessing the web service is now very easy as we have a bean factory for it that will expose it
as AccountService interface. We can wire this up in Spring:
The above is slightly simplified in that JAX-WS requires endpoint interfaces and
implementation classes to be annotated with @WebService, @SOAPBinding etc
annotations. This means that you cannot (easily) use plain Java interfaces and
implementation classes as JAX-WS endpoint artifacts; you need to annotate them
accordingly first. Check the JAX-WS documentation for details on those
requirements.
28.6 JMS
It is also possible to expose services transparently using JMS as the underlying
communication protocol. The JMS remoting support in the Spring Framework is pretty basic -
it sends and receives on the same thread and in the same non-transactional Session, and
as such throughput will be very implementation dependent. Note that these single-threaded
and non-transactional constraints apply only to Spring’s JMS remoting support. See
Chapter 30, JMS (Java Message Service) for information on Spring’s rich support for JMS-
based messaging.
The following interface is used on both the server and the client side.
package com.foo;
The following simple implementation of the above interface is used on the server-side.
package com.foo;
This configuration file contains the JMS-infrastructure beans that are shared on both the client
and server.
<bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://ep-t43:61616"/>
</bean>
</beans>
<bean id="checkingAccountService"
class="org.springframework.jms.remoting.JmsInvokerServiceExporter">
<property name="serviceInterface"
value="com.foo.CheckingAccountService"/>
<property name="service">
<bean class="com.foo.SimpleCheckingAccountService"/>
</property>
</bean>
<bean
class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="queue"/>
<property name="concurrentConsumers" value="3"/>
<property name="messageListener" ref="checkingAccountService"/>
</bean>
</beans>
package com.foo;
import org.springframework.context.support.ClassPathXmlApplicationContext;
<bean id="checkingAccountService"
class="org.springframework.jms.remoting.JmsInvokerProxyFactoryBean">
<property name="serviceInterface"
value="com.foo.CheckingAccountService"/>
<property name="connectionFactory" ref="connectionFactory"/>
<property name="queue" ref="queue"/>
</bean>
</beans>
package com.foo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
28.7 AMQP
Refer to the Spring AMQP Reference Document 'Spring Remoting with AMQP' section for
more information.
Offering a proxy with all interfaces implemented by the target usually does not matter in the
local case. But when exporting a remote service, you should expose a specific service
interface, with specific operations intended for remote usage. Besides internal callback
interfaces, the target might implement multiple business interfaces, with just one of them
intended for remote exposure. For these reasons, we require such a service interface to be
specified.
This is a trade-off between configuration convenience and the risk of accidental exposure of
internal methods. Always specifying a service interface is not too much effort, and puts you on
the safe side regarding controlled exposure of specific methods.
28.9 Considerations when choosing a technology
Each and every technology presented here has its drawbacks. You should carefully consider
your needs, the services you are exposing and the objects you’ll be sending over the wire
when choosing a technology.
When using RMI, it’s not possible to access the objects through the HTTP protocol, unless
you’re tunneling the RMI traffic. RMI is a fairly heavy-weight protocol in that it supports full-
object serialization which is important when using a complex data model that needs
serialization over the wire. However, RMI-JRMP is tied to Java clients: It is a Java-to-Java
remoting solution.
Spring’s HTTP invoker is a good choice if you need HTTP-based remoting but also rely on
Java serialization. It shares the basic infrastructure with RMI invokers, just using HTTP as
transport. Note that HTTP invokers are not only limited to Java-to-Java remoting but also to
Spring on both the client and server side. (The latter also applies to Spring’s RMI invoker for
non-RMI interfaces.)
Hessian and/or Burlap might provide significant value when operating in a heterogeneous
environment, because they explicitly allow for non-Java clients. However, non-Java support is
still limited. Known issues include the serialization of Hibernate objects in combination with
lazily-initialized collections. If you have such a data model, consider using RMI or HTTP
invokers instead of Hessian.
JMS can be useful for providing clusters of services and allowing the JMS broker to take care
of load balancing, discovery and auto-failover. By default: Java serialization is used when
using JMS remoting but the JMS provider could use a different mechanism for the wire
formatting, such as XStream to allow servers to be implemented in other technologies.
Last but not least, EJB has an advantage over RMI in that it supports standard role-based
authentication and authorization and remote transaction propagation. It is possible to get RMI
invokers or HTTP invokers to support security context propagation as well, although this is not
provided by core Spring: There are just appropriate hooks for plugging in third-party or
custom solutions here.
28.10.1 RestTemplate
Invoking RESTful services in Java is typically done using a helper class such as Apache
HttpComponents HttpClient. For common REST operations this approach is too low level
as shown below.
httpClient.executeMethod(post);
if (HttpStatus.SC_CREATED == post.getStatusCode()) {
Header location = post.getRequestHeader("Location");
if (location != null) {
System.out.println("Created new booking at :" + location.getValue());
}
}
RestTemplate provides higher level methods that correspond to each of the six main HTTP
methods that make invoking many RESTful services a one-liner and enforce REST best
practices.
The names of RestTemplate methods follow a naming convention, the first part indicates
what HTTP method is being invoked and the second part indicates what is returned. For
example, the method getForObject() will perform a GET, convert the HTTP response into
an object type of your choice and return that object. The method postForLocation() will do
a POST, converting the given object into a HTTP request and return the response HTTP
Location header where the newly created object can be found. In case of an exception
processing the HTTP request, an exception of the type RestClientException will be thrown;
this behavior can be changed by plugging in another ResponseErrorHandler implementation
into the RestTemplate.
The exchange and execute methods are generalized versions of the more specific methods
listed above them and can support additional combinations and methods, like HTTP PATCH.
However, note that the underlying HTTP library must also support the desired combination.
The JDK HttpURLConnection does not support the PATCH method, but Apache
HttpComponents HttpClient version 4.2 or later does. They also enable RestTemplate to
read an HTTP response to a generic type (e.g. List<Account>), using a
ParameterizedTypeReference, a new class that enables capturing and passing generic
type info.
Objects passed to and returned from these methods are converted to and from HTTP
messages by HttpMessageConverter instances. Converters for the main mime types are
registered by default, but you can also write your own converter and register it via the
messageConverters() bean property. The default converter instances registered with the
template are ByteArrayHttpMessageConverter, StringHttpMessageConverter,
FormHttpMessageConverter and SourceHttpMessageConverter. You can override these
defaults using the messageConverters() bean property as would be required if using the
MarshallingHttpMessageConverter or MappingJackson2HttpMessageConverter.
Each method takes URI template arguments in two forms, either as a String variable-length
argument or a Map<String,String>. For example,
using a Map<String,String>.
To create an instance of RestTemplate you can simply call the default no-arg constructor.
This will use standard Java classes from the java.net package as the underlying
implementation to create HTTP requests. This can be overridden by specifying an
implementation of ClientHttpRequestFactory. Spring provides the implementation
HttpComponentsClientHttpRequestFactory that uses the Apache HttpComponents
HttpClient to create requests. HttpComponentsClientHttpRequestFactory is configured
using an instance of org.apache.http.client.HttpClient which can in turn be configured
with credentials information or connection pooling functionality.
Note that the java.net implementation for HTTP requests may raise an exception
when accessing the status of a response that represents an error (e.g. 401). If this
is an issue, switch to HttpComponentsClientHttpRequestFactory instead.
The previous example using Apache HttpComponents HttpClient directly rewritten to use
the RestTemplate is shown below
uri = "http://example.com/hotels/{id}/bookings";
To use Apache HttpComponents instead of the native java.net functionality, construct the
RestTemplate as follows:
and allows you to manipulate the request headers and write to the request body. When using
the execute method you do not have to worry about any resource management, the template
will always close the request and handle any errors. Refer to the API documentation for more
information on using the execute method and the meaning of its other method arguments.
The String URI variants accept template arguments as a String variable-length argument or
as a Map<String,String>. They also assume the URL String is not encoded and needs to
be encoded. For example the following:
The UriComponentsBuilder class can be used to build and encode the URI including
support for URI templates. For example you can start with a URL String:
.scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}")
.build()
.expand("42", "21")
.encode();
Perhaps most importantly, the exchange() method can be used to add request headers and
read response headers. For example:
In the above example, we first prepare a request entity that contains the MyRequestHeader
header. We then retrieve the response, and read the MyResponseHeader and body.
// Indicate whether the given class and media type can be read by this
converter.
boolean canRead(Class<?> clazz, MediaType mediaType);
// Indicate whether the given class and media type can be written by this
converter.
boolean canWrite(Class<?> clazz, MediaType mediaType);
// Read an object of the given type from the given input message, and
returns it.
T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException,
HttpMessageNotReadableException;
Concrete implementations for the main media (mime) types are provided in the framework
and are registered by default with the RestTemplate on the client-side and with
AnnotationMethodHandlerAdapter on the server-side.
StringHttpMessageConverter
An HttpMessageConverter implementation that can read and write Strings from the HTTP
request and response. By default, this converter supports all text media types ( text/*), and
writes with a Content-Type of text/plain.
FormHttpMessageConverter
An HttpMessageConverter implementation that can read and write form data from the HTTP
request and response. By default, this converter reads and writes the media type
application/x-www-form-urlencoded. Form data is read from and written into a
MultiValueMap<String, String>.
ByteArrayHttpMessageConverter
An HttpMessageConverter implementation that can read and write byte arrays from the
HTTP request and response. By default, this converter supports all media types ( */*), and
writes with a Content-Type of application/octet-stream. This can be overridden by
setting the supportedMediaTypes property, and overriding getContentType(byte[]).
MarshallingHttpMessageConverter
An HttpMessageConverter implementation that can read and write XML using Spring’s
Marshaller and Unmarshaller abstractions from the org.springframework.oxm package.
This converter requires a Marshaller and Unmarshaller before it can be used. These can
be injected via constructor or bean properties. By default this converter supports ( text/xml)
and ( application/xml).
MappingJackson2HttpMessageConverter
An HttpMessageConverter implementation that can read and write JSON using Jackson’s
ObjectMapper. JSON mapping can be customized as needed through the use of Jackson’s
provided annotations. When further control is needed, a custom ObjectMapper can be
injected through the ObjectMapper property for cases where custom JSON
serializers/deserializers need to be provided for specific types. By default this converter
supports ( application/json).
MappingJackson2XmlHttpMessageConverter
An HttpMessageConverter implementation that can read and write XML using Jackson XML
extension’s XmlMapper. XML mapping can be customized as needed through the use of
JAXB or Jackson’s provided annotations. When further control is needed, a custom
XmlMapper can be injected through the ObjectMapper property for cases where custom XML
serializers/deserializers need to be provided for specific types. By default this converter
supports ( application/xml).
SourceHttpMessageConverter
An HttpMessageConverter implementation that can read and write
javax.xml.transform.Source from the HTTP request and response. Only DOMSource,
SAXSource, and StreamSource are supported. By default, this converter supports (
text/xml) and ( application/xml).
BufferedImageHttpMessageConverter
An HttpMessageConverter implementation that can read and write
java.awt.image.BufferedImage from the HTTP request and response. This converter
reads and writes the media type supported by the Java I/O API.
AsyncRestTemplate and Section 28.10.1, “RestTemplate”'s APIs are very similar; see
Table 28.1, “Overview of RestTemplate methods”. The main difference between those APIs is
that AsyncRestTemplate returns ListenableFuture wrappers as opposed to concrete
results.
// async call
Future<ResponseEntity<String>> futureEntity = template.getForEntity(
"http://example.com/hotels/{hotel}/bookings/{booking}", String.class,
"42", "21");
// register a callback
futureEntity.addCallback(new
ListenableFutureCallback<ResponseEntity<String>>() {
@Override
public void onSuccess(ResponseEntity<String> entity) {
//...
}
@Override
public void onFailure(Throwable t) {
//...
}
});