Ok here iam back to find a solution.
Iam trying Spring RestTemplate postForEntity method to send a Collection of instances. When attempting spring gives an error org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [com.abc.base.domai
n.dto.gift.GiftItemList Appriciate, if someone can tells me how to send a an ArrayList with spring resttemplate POST method.
RestTemplate bean:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="httpClientFactory"/>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean id="jsonViewResolver" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" >
<property name="objectMapper">
<ref bean="JacksonObjectMapper" />
</property>
<property name="supportedMediaTypes">
<list>
<bean class="org.springframework.http.MediaType">
<constructor-arg value="application" />
<constructor-arg value="json" />
<constructor-arg value="#{T(java.nio.charset.Charset).forName('UTF-8')}"/>
</bean>
</list>
</property>
</bean>
</list>
</property>
</bean>
<bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />
<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
<constructor-arg ref="httpClientParams"/>
</bean>
<bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">
<property name="connectionManagerClass" value="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager"/>
</bean>
<bean id="httpClientFactory" class="org.springframework.http.client.CommonsClientHttpRequestFactory">
<constructor-arg ref="httpClient"/>
</bean>
Instance that iam trying to POST,
public class GiftItem implements Entity, Serializable {
private static final long serialVersionUID = 1L;
private String redeemLocation;
private String itemName;
private String itemDescription;
private String merchantName;
private Integer quantity;
private Integer imageId;
public GiftItem() {
super();
}
//with getters and setters
}
GiftItem instance wraaper class
public class GiftItemList implements Serializable {
private static final long serialVersionUID = -8202204714984099030L;
public GiftItemList() {
}
private List<GiftItem> giftItemList;
public List<GiftItem> getGiftItemList() {
return giftItemList;
}
public void setGiftItemList(List<GiftItem> giftItemList) {
this.giftItemList = giftItemList;
}
}
this is how i use it,
public BaseResponse sendGiftEmail(final String token, final User sender,final String message, final GiftItemList giftItemList) {
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("token", token);
map.add("sender", sender);
map.add("message", message);
map.add("giftItemList", giftItemList);
return getRestTemplate().postForEntity(
"http://localhost:8080/notification/api/notification/send_gift_email",
map, BaseResponse.class).getBody();
}
and the error i am getting,
org.springframework.http.converter.HttpMessageNotWritableException: Could not write request: no suitable HttpMessageConverter found for request type [com.abc.base.domain.dto.gift.GiftItemList]
at org.springframework.http.converter.FormHttpMessageConverter.write Part(FormHttpMessageConverter.java:310)
at org.springframework.http.converter.FormHttpMessageConverter.write Parts(FormHttpMessageConverter.java:270)
at org.springframework.http.converter.FormHttpMessageConverter.write Multipart(FormHttpMessageConverter.java:260)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:200)
at org.springframework.http.converter.FormHttpMessageConverter.write(FormHttpMessageConverter.java:1)
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.postForEntity(RestTemplate.java:302)
at com.tapgift.gift.client.impl.GiftClientImpl.sendGiftNotifications(GiftClientImpl.java:101)
pom:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.2</version>
</dependency>
almost forgot receiver controller,
#RequestMapping(value = "/notification/send_gift_email", method = RequestMethod.POST)
public #ResponseBody BaseResponse sendGiftEmail(#RequestParam("token") String token, #RequestParam("sender")final User sender, #RequestParam("message")final String message,#RequestParam("giftItemList") GiftItemList giftItemList) {
}
You have to add MappingJacksonHttpMessageConveter to your messageCoverter :
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new MappingJacksonHttpMessageConverter());
restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
You also need to add the dependency for :
jackson-core-asl-x.x.x.jar & jaackson.mapper.asl-x.x.x.jar
Another thing, you have to make sure that your class have the same attribute as your JSON properties. For example :
{"data":{"ticket":"TICKET_870299cf98e227abdbd5f9b7064390c5723a0c6a"}}
To fill your class properties, they have to be like this :
person.java
public class person {
private Data data;
public Data getData() {
return data;
}
public void setData(Data data) {
this.data = data;
}
}
data.java
public class Data {
private String ticket;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
}
Finaly in your application your add :
person entity = restTemplate.postForObject(url, requestEntity,
person.class);
requestEntity is a String that contains your request body (JSON in my case).
Hope that helped !
Related
My batch job will generate 2 text files with string format per line. I created a reader
<bean id="myMultiResourceReader"
class=" org.springframework.batch.item.file.MultiResourceItemReader">
<property name="resources" value="file:D:/MY/sample/*.txt" />
</bean>
<bean id="myFinalWriter" class="org.springframework.batch.item.file.FlatFileItemWriter"
scope="step">
<property name="resource" value="${test.file3}" />
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</property>
<property name="footerCallback" ref="myFinalCustomItemWriter" />
<property name="headerCallback" ref="myFinalCustomItemWriter" />
</bean>
<bean id="myFinalCustomItemWriter" class="my.process.MyWriter"
scope="step">
<property name="delegate" ref="myFinalWriter" />
<property name="stepContext" value="#{stepExecution.stepName}" />
</bean>
I was getting this error:
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.sun.proxy.$Proxy68 implementing org.springframework.batch.item.file.ResourceAwareItemWriterItemStream,org.springframework.beans.factory.InitializingBean,org.springframework.batch.item.ItemStreamWriter,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'org.springframework.batch.item.file.FlatFileItemWriter' for property 'delegate'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy68 implementing org.springframework.batch.item.file.ResourceAwareItemWriterItemStream,org.springframework.beans.factory.InitializingBean,org.springframework.batch.item.ItemStreamWriter,org.springframework.batch.item.ItemStream,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [org.springframework.batch.item.file.FlatFileItemWriter] for property 'delegate': no matching editors or conversion strategy found
Basically I just want to combine two plain file, and append the total count at footer. Then delete away the both input file. Can help?
MyWriter.java
public class MyWriter implements ItemWriter<String>, FlatFileFooterCallback, FlatFileHeaderCallback, ItemStream{
private static Logger log = Logger.getLogger(MyWriter.class);
private FlatFileItemWriter<String> delegate;
private int recordCount = 0;
private String stepContext;
public void writeFooter(Writer writer) throws IOException {
writer.write("#" + recordCount);
}
public void writeHeader(Writer writer) throws IOException {
writer.write("#" + StringUtil.getSysDate());
}
public void setDelegate(FlatFileItemWriter<String> delegate) {
this.delegate = delegate;
}
public void write(List<? extends String> list) throws Exception {
int chunkRecord = 0;
for (String item : list) {
chunkRecord++;
}
delegate.write(list);
recordCount += chunkRecord;
}
public void close() throws ItemStreamException {
this.delegate.close();
}
public void open(ExecutionContext arg0) throws ItemStreamException {
this.delegate.open(arg0);
}
public void update(ExecutionContext arg0) throws ItemStreamException {
this.delegate.update(arg0);
}
public void setStepContext(String stepContext) {
this.stepContext = stepContext;
}
}
As Luca Basso Ricci already pointed out, the problem is your delegate definition in MyWriter. Since Spring creates proxies for it beans, it will not recognize your FlatFileItemReader as an actual instance of FlatFileItemWriter and, therefore, the setDelegate(FlatFileItemWriter delegate) will fail.
Use an ItemStreamWriter in MyWriter. As you see in the exception message, the created proxy does provide this interface. Hence, it can be inserted
This will solve the delegation to write, open, close, and update method. In order to write the header and footer, you need to implement a HeaderCallback and FooterCallback and set it directly in the definition of your FlatFileItemWriter.
Implementing the HeaderCallback is not a problem since you only set the systemdate.
As FooterCallback, make your own Bean. Use it in the FlatFileItemWriter to write the footer. Add an "increaseCount" method to it and use it in your MyWriter Bean to increase the written count.
public void write(List<? extends String> list) throws Exception {
myFooterCallback.increaseCount(list.size());
delegate.write(list);
}
Another possible option would be to directly extend MyWriter from FlatFileItemWriter:
public class MyWriter extends FlatFileItemWriter<String> implements FlatFileFooterCallback, FlatFileHeaderCallback{
private static Logger log = Logger.getLogger(MyWriter.class);
private int recordCount = 0;
private String stepContext;
public void writeFooter(Writer writer) throws IOException {
writer.write("#" + recordCount);
}
public void writeHeader(Writer writer) throws IOException {
writer.write("#" + StringUtil.getSysDate());
}
public void afterPropertiesSet() {
setFooterCallback(this);
setHeaderCallback(this);
super.afterPropertiesSet();
}
public void write(List<? extends String> list) throws Exception {
super.write(list);
recordCount += list.size();
}
}
Configuration in your XML would look like this:
<bean id="myFinalCustomItemWriter" class="my.process.MyWriter" scope="step">
<property name="resource" value="${test.file3}" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.PassThroughLineAggregator" />
</property>
<property name="stepContext" value="#{stepExecution.stepName}" />
</bean>
I am using the below Spring configuration in order to connect to mongoDB
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="${mongodb.dbname}"/>
</bean>
<bean class="com.mongodb.MongoURI" id="mongoUri">
<constructor-arg value="${mongodb.url}" />
</bean>
<bean class="com.mongodb.Mongo" id="mongo">
<constructor-arg ref="mongoUri" />
</bean>
where mongo.url=mongodb://<user>:<password>#<host>:27017
However I'm getting an authetication error.
My understanding was that MongoUI can take a URL in the above format.
I know that mongoTemplate can accept userCredentials object however I would need to extract them from the URL first and i'm not sure how to do that in the configuration.
Any idea how can I change my config above to suppot this assuming mongo.url format cannot be changed?
found the solution using Spring Expression Language
<bean id="mongoTemplate" class="org.springframework.data.document.mongodb.MongoTemplate">
<constructor-arg name="mongo" ref="mongo"/>
<constructor-arg name="databaseName" value="${mongodb.dbname}"/>
<constructor-arg name="userCredentials" ref="mongoCredentials"/>
</bean>
<bean id="mongoCredentials" class="org.springframework.data.authentication.UserCredentials">
<property name="username" value="#{mongoURI.username}" />
<property name="password" value="#{new java.lang.String(mongoURI.password)}" />
</bean>
<bean class="com.mongodb.MongoURI" id="mongoURI">
<constructor-arg value="${mongodb.url}" />
</bean>
<bean class="com.mongodb.Mongo" id="mongo">
<constructor-arg ref="mongoURI" />
</bean>
If you want to add authntication using java config
#Configuration
#EnableMongoRepositories("path.to.your.repository")
public class MongoConfig extends AbstractMongoConfiguration
{
#Value("${mongodb.name}")
private String dbName;
#Value("${mongodb.host}")
private String host;
#Value("${mongodb.port}")
private Integer port;
#Value("${mongodb.username}")
private String userName;
#Value("${mongodb.password}")
private String password;
#Override
protected String getDatabaseName()
{
return this.dbName;
}
#Override
public Mongo mongo() throws Exception
{
return new MongoClient(this.host, this.port);
}
#Override
#Bean
public SimpleMongoDbFactory mongoDbFactory() throws Exception
{
return new SimpleMongoDbFactory(mongo(), getDatabaseName());
}
#Override
#Bean
public MongoTemplate mongoTemplate() throws Exception
{
final UserCredentials userCredentials = new UserCredentials(this.userName, this.password);
final MongoTemplate mongoTemplate = new MongoTemplate(mongo(), getDatabaseName(), userCredentials);
mongoTemplate.setWriteConcern(WriteConcern.SAFE);
return mongoTemplate;
}
}
To update #Lealem Admassu's answer for java config, in Mongo 3 they changed the API, and now it is recommended to use mongo's MongoCredentials instead of UserCredentials.
Here there is a simple example of how to get a MongoClient:
http://docs.spring.io/spring-data/mongodb/docs/current/reference/html/#mongo.mongo-3.authentication
The next code can be done modular, but more or less this works for me (I needed a MongoTemplate):
public MongoTemplate getMongoTemplate(String host, int port,
String authenticationDB,
String database,
String user, char[] password)
throws UnknownHostException {
return new MongoTemplate(
new SimpleMongoDbFactory(
new MongoClient(
new ServerAddress(host, port),
Collections.singletonList(
MongoCredential.createCredential(
user,
authenticationDB,
password
)
)
),
database
)
);
}
I have the aspect(see below) which should log actions(create, update, delete) in db. Depends on action logging happens in a preProcess or postProcess method. I shouldn't log anything if some fail happens through these actions. I.e. if create didn't happened, then there is no need to logging it.
I tried to tested it. I throw RunTimeException in the join point and expect that there is no new log in db. Unfortunately, new log is saved in spite of exception in the join point.
Aspect:
#Component
#Aspect
public class LoggingAspect {
#Autowired
private ApplicationContext appContext;
#Autowired
private LoggingService loggingService;
#Around("#annotation(Loggable)")
#Transactional
public void saveActionMessage(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
Loggable m = ms.getMethod().getAnnotation(Loggable.class);
LoggingStrategy strategy = appContext.getBean(m.strategy());
Object argument = joinPoint.getArgs()[0];
strategy.preProcess(argument);
joinPoint.proceed();
strategy.postProcess(argument);
}
}
TestApplicationConfig:
<context:spring-configured/>
<import resource="applicationConfig-common.xml"/>
<import resource="applicationConfig-security.xml"/>
<aop:aspectj-autoproxy/>
<util:map id="testValues">
<entry key="com.exadel.mbox.test.testSvnFile" value="${svnFolder.configPath}${svnRoot.file[0].fileName}"/>
<entry key="com.exadel.mbox.test.testCommonRepositoryPath" value="${svnRoot.commonRepositoryPath}"/>
<entry key="com.exadel.mbox.test.testMailFile" value="${mailingList.configPath}"/>
</util:map>
<context:component-scan base-package="com.exadel.report.common" />
<!-- Jpa Repositories -->
<jpa:repositories base-package="com.exadel.report.common.dao" />
<tx:annotation-driven proxy-target-class="true"
transaction-manager="txManager" mode="aspectj"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- Data Source -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<!-- Entity Manager -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect"/>
</bean>
</property>
<property name="persistenceUnitName" value="exviewer-test"/>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
[Update]
LoggingStrategy:
public interface LoggingStrategy {
public void preProcess(Object obj);
public void postProcess(Object obj);
}
BaseLoggingStrategy:
public class BaseLoggingStrategy implements LoggingStrategy {
#Override
public void preProcess(Object obj) {}
#Override
public void postProcess(Object obj) {}
}
UpdateProcessStrategy:
#Service
public class UpdateProcessStrategy extends BaseLoggingStrategy {
#Autowired
private LoggingService loggingService;
#Autowired
private UserService userService;
#Autowired
DeviceService deviceService;
private Device currentDevice;
#Override
#Transactional
public void preProcess(Object obj) {
currentDevice = (Device) obj;
Device previousDevice = deviceService.getById(currentDevice.getId());
String deviceDataBeforeUpdate = deviceService.getDeviceDetailsInJSON(previousDevice);
String deviceDataAfterUpdate = deviceService.getDeviceDetailsInJSON(currentDevice);
String login = userService.getCurrentUser().getLogin();
String actionMessage = LoggingMessages.DEVICE_UPDATE.name();
loggingService.save(
new Logging(
login,
actionMessage,
deviceDataBeforeUpdate,
deviceDataAfterUpdate,
new Date())
);
}
#Override
public void postProcess(Object obj) {}
}
Class intercepted by aspcet:
#Service
public class DeviceService {
#Loggable(value = LoggingMessages.DEVICE_CREATE, strategy = CreateProcessStrategy.class)
#Transactional
public void create(Device device) {
createOrUpdate(device);
}
#Loggable(value = LoggingMessages.DEVICE_UPDATE, strategy = UpdateProcessStrategy.class)
#Transactional
public void update(Device device) {
createOrUpdate(device);
}
private void createOrUpdate(Device device) {
deviceRepository.save(device);
}
#Loggable(value = LoggingMessages.DEVICE_REMOVE, strategy = RemoveProcessStrategy.class)
public void remove(Long deviceId) {
deviceRepository.delete(deviceId);
}
}
Loggable annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Loggable {
LoggingMessages value();
Class<? extends LoggingStrategy> strategy();
}
Log for update action contains:
id, created_dtm, action(DEVICE_UPDATE), device_data_before_action_on_the_device(in json format), device_data_after_action_on_the_device(in json format), created_by.
Disclaimer: Actually I am not a Spring expert, maybe someone else can help you out here. My field of expertise it AspectJ, which is how I found your question.
Anyway, you have two issues here:
#Transactional annotation on your aspect's advice LoggingAspect.saveActionMessage(..). Actually I have no idea if this works at all (I found no example using #Transactional on an aspect method/advice on the web, but maybe I searched in the wrong way) because declarative transaction handling in Spring is implemented via proxy-based technology, just like Spring AOP. Read the chapter 12 about transaction management in the Spring manual for further details, especially chapter 12.5.1. I am pretty sure you will find a way to do what you want there.
Nested transactions, because e.g. UpdateProcessStrategy.preProcess(..) is called by the very advice which is meant to be transactional, but is declared #Transactional too. So you have a transaction within a transaction. How Spring handles this, I have no idea, but maybe this tutorial about Spring transaction propagation contains enlightening details.
The Spring manual lists several means to implement transactional behaviour: programmatically, declaratively via annotations, XML-based <tx:advice> stuff and so forth. I don't know which way is the best for you, I merely wanted to provide some general hints.
I am using routing data sources, and my create operations are annotated with #Transactional annotations. But i noticed that transaction does not begin or commit. Following is my routing data source configuration.
<bean id="routingDataSource" class="com.test.dataaccess.base.dao.CustomerRoutingDataSource">
<property name="defaultTargetDataSource" ref="testDataSource" />
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="0" value-ref="testDataSource" />
</map>
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="customerTransactionManager">
<property name="entityManagerFactory" ref="customerEntityManagerFactory" />
</bean>
Same data source i am using with my org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.
I am adding another datasources to routing data sources at deployment time as follows.
Spring transaction management does not works.
#Component
public class CustomerDataSourcePostProcessor implements ApplicationListener {
#Autowired
DatasourcesDAO datasourcesDAO;
#Autowired
#Qualifier("customerEntityManagerFactory")
private LocalContainerEntityManagerFactoryBean testContentEntityManagerFactory;
#Autowired
#Qualifier("routingDataSource")
private CustomerRoutingDataSource routingDataSource;
#Autowired
#Qualifier("customerTransactionManager")
private JpaTransactionManager customerTransactionManager;
private static final Logger LOGGER = LoggerFactory.getLogger(CustomerDataSourcePostProcessor.class);
public void onApplicationEvent(ApplicationEvent e) {
if (e instanceof ContextRefreshedEvent) {
loadCustomerDBConfigForServer();
}
}
private void loadCustomerDBConfigForServer() {
Map<Object, Object> databaseConfig = loadCustomerDatabaseConfig();
routingDataSource.setTargetDataSources(databaseConfig);
routingDataSource.afterPropertiesSet();
testContentEntityManagerFactory.setDataSource(routingDataSource);
testContentEntityManagerFactory.afterPropertiesSet();
EntityManagerFactory emf =testContentEntityManagerFactory.getObject(); // transaction not begin possible root cause one
customerTransactionManager.setEntityManagerFactory(emf);
customerTransactionManager.afterPropertiesSet();
}
}
first of all, i've already read all questions related with this topic in stackoverflow, but i can't find the solution. I have been working on this for days.
I have this restFull web app built with spring mvc. When i try to retrieve a User i get this error:
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.src.model.UserDTO] and content type [text/html;charset=UTF-8]
org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessag eConverterExtractor.java:84)
org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:627)
org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:454)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:385)
com.src.web.controller.HomeController.getHome(HomeController.java:42)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:100)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:604)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:565)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
The request never reach the server, so the problem isn't the response content-type, because there is no response. So i am loss there. I show here my classes and configs, if some info is missed, please let me know, and i will update the question. Thanks!
Client controller:
#Controller
public class HomeController extends GenericAbstractController{
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String getHome(HttpServletRequest request, Model model) {
Principal userPrincipal = request.getUserPrincipal();
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_XML);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
headers.setAccept(acceptableMediaTypes);
HttpEntity<UserDTO> entity = new HttpEntity<UserDTO>(headers);
ResponseEntity<UserDTO> result = restTemplate.exchange("http://localhost:8080/rideon/users/{id}",
HttpMethod.GET, entity, UserDTO.class, userPrincipal.getName());
model.addAttribute("user", result.getBody());
return "home";
}
Server controller:
#Controller
public class UsersController {
private static final Logger LOGGER = LoggerFactory.getLogger(UsersController.class);
#Autowired
private UserService userService;
#RequestMapping(value = "users/{id}", method = RequestMethod.GET, headers = "Accept=application/xml")
#ResponseBody
public UserDTO getUser(#PathVariable("id") String id) {
return userService.getUserById(id);
}
User:
#XmlRootElement
#Entity(name = "users")
public class UserDTO implements Serializable {
#Id
private String email;
private String password;
private String name;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Application-context:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller" />
<property name="unmarshaller" ref="jaxbMarshaller" />
</bean>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter" />
<bean class="org.springframework.http.converter.FormHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter" />
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter" />
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.src.model.UserDTO</value>
<value>com.src.model.MultimediaDTO</value>
<value>com.src.model.BicycleDTO</value>
<value>com.src.model.FriendshipRequestDTO</value>
</list>
</property>
</bean>
Dependencies:
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.13</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.2.9</version>
<scope>runtime</scope>
</dependency>
Ok I finally found the problem. The response is actually an html error page generated by a wrong security configuration. Indeed the above code seems to be ok. Thanks!