Spring configuration - mvc:annotation-driven, AnnotationMethodHandlerAdapter, and JSON - json

Thanks in advance any help.
I'm trying to get one of my controller methods to return JSON. Starting off with a simple test:
#RequestMapping(value="/myReqPath", method=RequestMethod.GET)
#ResponseBody
public Map<String, String> myJsonMethod() {
Map<String, String> response = new TreeMap<String, String>();
response.put("test", "test");
return response;
}
It's my understanding that I need <mvc:annotation-driven/> added to my servlet context to accomplish this. The problem is when I add it, it breaks my custom AnnotationMethodHandlerAdapter.
[B]How do I extract and add the needed parts of <mvc:annotation-driven/> to return JSON from the controller?[/B]
Here are the pertinent parts of my servlet config:
<!--Skipping this for now...
<mvc:annotation-driven/>
-->
<!-- JSON Marshaling -->
<util:constant id="jsonBasicClassIntrospector"
static-field="org.codehaus.jackson.map.introspect.BasicClassIntrospector.instance" />
<bean id="jsonJaxbAnnotationIntrospector"
class="org.codehaus.jackson.xc.JaxbAnnotationIntrospector" />
<bean id="jsonVisibilityChecker"
class="org.codehaus.jackson.map.introspect.VisibilityChecker.Std"
factory-method="defaultInstance" />
<bean id="jsonDefaultTypeFactory"
class="org.codehaus.jackson.map.type.TypeFactory"
factory-method="defaultInstance" />
<bean id="jsonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper">
<property name="serializationConfig">
<bean class="org.codehaus.jackson.map.SerializationConfig">
<constructor-arg ref="jsonBasicClassIntrospector" />
<constructor-arg ref="jsonJaxbAnnotationIntrospector" />
<constructor-arg ref="jsonVisibilityChecker" />
<constructor-arg><null/></constructor-arg>
<constructor-arg><null/></constructor-arg>
<constructor-arg ref="jsonDefaultTypeFactory" />
<constructor-arg><null/></constructor-arg>
</bean>
</property>
<property name="deserializationConfig">
<bean class="org.codehaus.jackson.map.DeserializationConfig">
<constructor-arg ref="jsonBasicClassIntrospector" />
<constructor-arg ref="jsonJaxbAnnotationIntrospector" />
<constructor-arg ref="jsonVisibilityChecker" />
<constructor-arg><null/></constructor-arg>
<constructor-arg><null/></constructor-arg>
<constructor-arg ref="jsonDefaultTypeFactory" />
<constructor-arg><null/></constructor-arg>
</bean>
</property>
</bean>
...
<!-- My custom AnnotationMethodHandlerAdapter... -->
<bean id="sessionArgResolver" class="com.SessionParamArgumentResolver"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolver" ref="sessionArgResolver"/>
</bean>
As it stands, my controller method is invoked however, the browser returns http status 406:
406 Not Acceptable - [url]http://localhost:8080/myApp/myReqPath[/url]

If you already have a custom AnnotationMethodHandlerAdapter declaration, you can just add a list of HttpMessageConverters to it:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolver" ref="sessionArgResolver"/>
<property name = "messageConverters">
<list>
<bean
class = "org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name = "objectMapper" ref = "jsonObjectMapper" />
</bean>
</list>
</property>
</bean>

Related

Return a JSONObject through Spring MappingJackson2JsonView

I Have xml and json output view for my spring project. I'm using spring 4 version and This is the my ViewResolver xml file.
<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="order" value="1" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<!-- JSON View -->
<bean
class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
</bean>
<!-- JAXB XML View -->
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.rest.dto.SportInfoDtoList</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</list>
</property>
<property name="ignoreAcceptHeader" value="true" />
</bean>
I want to pass Jackson JSONObject through my controller using ModelAndView.
#RequestMapping(value="stat", method=RequestMethod.POST)
public ModelAndView getSeasonteamStat(#ModelAttribute(value="statDto") StatDto statDto){
ModelAndView model = new ModelAndView();
try{
String seasonteamstatStr = GuideStatClient.getSeasonTeamStats();
JSONObject seasonteamstat = new JSONObject(seasonteamstatStr);
model.addObject("seasonteamstat", seasonteamstat);
return model;
} catch (Exception e){
return model;
}
}
If I return seasonteamstatStr it will return successfully. But I need to pass this string as a json objet. This is a huge object so I dont want to map it into java objects using JAXB.
So is there have any way to pass this string as a json. I tried jackson and gson JSONObject. Thanks in advance
Annotate your method with #ResponseBody which indicates a method return value should be bound to the web response body and change the return type to String

neo4j + mysql in spring data transactions not working

I am trying to build an application using both MySQL and neo4j.
Currently I succeed on saving an entity in both of the databases, but when I try to create a rollback only MySQL changes are rollbacked.
I'm not sure if the mode="proxy" configuration for the transactions can even work for neo4j, can someone approve/deny?
I'm using the #Transactional annotation over the relevant method, and I initiate a rollback by throwing a RuntimeException, which as I mentioned causes a rollback on MySQL.
My Configurations:
<neo4j:config graphDatabaseService="graphDatabaseService" entityManagerFactory="entityManagerFactory"/>
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg index="0" value="http://localhost:7474/db/data"/>
</bean>
<context:annotation-config/>
<context:component-scan base-package="...">
<neo4j:repositories base-package="..."/>
<jpa:repositories base-package="..."
entity-manager-factory-ref="entityManagerFactory"
transaction-manager-ref="transactionManager"/>
<tx:annotation-driven mode="proxy" transaction-manager="transactionManager"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="persistenceUnitName" value="hibernatePersistenceUnit"/>
<property name="packagesToScan" value="..."/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="database" value="MYSQL"/>
</bean>
</property>
</bean>
<!-- Database -->
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/..."/>
<property name="lookupOnStartup" value="true"/>
<property name="proxyInterface" value="javax.sql.DataSource"/>
</bean>
<!-- Declare a transaction manager-->
<bean id="transactionManager" class="org.springframework.data.transaction.ChainedTransactionManager">
<constructor-arg>
<list>
<ref bean="transactionManagerMysql"/>
<ref bean="transactionManagerNeo4j"/>
</list>
</constructor-arg>
</bean>
<bean id="transactionManagerMysql" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean id="transactionManagerNeo4j" class="org.springframework.data.neo4j.config.JtaTransactionManagerFactoryBean">
<constructor-arg ref="graphDatabaseService" />
</bean>

Spring Social Linkedin - SignIn

I am new to Spring social and trying to config spring social signin for linkedin.
My spring config file below,
<context:component-scan base-package="com.tc.web">
<context:include-filter type="regex"
expression="(service|controller|component)\..*" />
</context:component-scan>
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support. ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean
class="org.springframework.social.linkedin.connect .LinkedInConnectionFactory">
<constructor-arg value="key........" />
<constructor-arg value="secret .........." />
</bean>
</list>
</property>
</bean>
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt .Encryptors"
factory-method="noOpText" />
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.Jdb cUsersConnectionRepository">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="textEncryptor" />
</bean>
<bean id="connectionRepository" factory-method="createConnectionRepository"
factory-bean="usersConnectionRepository" scope="request">
<constructor-arg value="#{request.userPrincipal.name}" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean id="signInAdapter" class="com.tc.web.social.signin.SocialSignInAdapte r" />
<bean class="org.springframework.social.connect.web.Prov iderSignInController">
<!-- relies on by-type autowiring for the constructor-args -->
<constructor-arg ref="signInAdapter" />
<property name="applicationUrl" value="link" />
<property name="signUpUrl" value="link" />
<property name="signInUrl" value="link" />
</bean>
My SocialSignInAdapter.java is,
public class SocialSignInAdapter implements SignInAdapter{
#Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
System.out.println("User Id is ===>>> "+userId);
System.out.println("Connection is ====>>> "+connection);
return null;
}
}
In Login.jsp,
<li class="linkedin"> </li>
When I click the above linkedin link, i get 404 error.
I guess my app is unable to find the ProviderSignInController for the request, ://dom:8080/myApp/signin/linkedin.
I suspect the below config in spring xml.
<context:component-scan base-package="com.tc.web">
<context:include-filter type="regex"
expression="(service|controller|component)\..*" />
</context:component-scan>
I have all my controller inside the package com.tc.web. But the ProviderSignInController is in Spring package and my app is unable to find it.
I tried the below as well.
<context:component-scan base-package="com.tc.web,org.springframework.social.con nect.web">
<context:include-filter type="regex"
expression="(service|controller|component)\..*" />
</context:component-scan>
I got ambigous mapping error for ProviderSignInController with the above config.
So, I removed the
<bean class="org.springframework.social.connect.web.Prov iderSignInController">
<!-- relies on by-type autowiring for the constructor-args -->
<constructor-arg ref="signInAdapter" />
<property name="applicationUrl" value="link" />
<property name="signUpUrl" value="link" />
<property name="signInUrl" value="link" />
</bean>
from my spring xml. But still I am getting the 404 error.
Could anyone help me on this please ..........
Thanks,
Baskar.S
The Controller that handles signin requests is org.springframework.social.connect.web.ProviderSignInController (present in spring-social-web-x.x.x.jar)
The Controller method is
#RequestMapping(value="/{providerId}", method=RequestMethod.POST)
public RedirectView signIn(#PathVariable String providerId, NativeWebRequest request)
So, as you can see, it only accepts POST requests. You will have to change the anchor link tag to a button that triggers a form submit.
e.g.
<form action="<c:url value="/signin/linkedin" />" method="POST" id="frmLiConnect"></form>
Secondly, in order for the Spring Controller, extend the ProviderSignInController with your own dummy Controller so that the Spring class is accessible.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.web.ProviderSignInController;
import org.springframework.social.connect.web.SignInAdapter;
import org.springframework.stereotype.Controller;
#Controller
public class SigninController extends ProviderSignInController {
#Autowired
public SigninController(ConnectionFactoryLocator connectionFactoryLocator,
UsersConnectionRepository usersConnectionRepository,
SignInAdapter signInAdapter) {
super(connectionFactoryLocator, usersConnectionRepository, signInAdapter);
// TODO Auto-generated constructor stub
}
}
For more details, you can also refer to the Spring Social Showcase examples at the below link.
https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase/src/main/java/org/springframework/social/showcase/signin
Hope this helps.

Spring WS - JMS backed endpoint - When endpoint not found

I have a Spring WS Endpoint which gets the payload from a JMS Queue. I use annotation based routing on my endpoint [based on payload root].
If for whatever reason, the routing doesn't happen [due to a typo etc], I only see a warning that there is "No Endpoint Found for Request SAAJSoapMessage". The main issue here is the message is lost! In my case, I would like an exception to be raised and fore the message to go to a Dead Letter Queue. The reliability is super critical here. What's the best way to achieve this. Here is my config:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616?jms.redeliveryPolicy.maximumRedeliveries=5" />
</bean>
<bean id="cachingConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="connectionFactory" />
</bean>
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory" />
<bean
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="cachingConnectionFactory" />
<property name="destinationName" value="profiler.request.queue" />
<property name="sessionTransacted" value="true"></property>
<property name="transactionManager" ref="local.transactionManager" />
<property name="messageListener">
<bean
class="org.springframework.ws.transport.jms.WebServiceMessageListener">
<property name="messageFactory" ref="messageFactory" />
<property name="messageReceiver" ref="messageDispatcher" />
</bean>
</property>
</bean>
<bean id="local.transactionManager"
class="org.springframework.jms.connection.JmsTransactionManager">
<!-- can also refer to amq.connectionFactory -->
<property name="connectionFactory" ref="cachingConnectionFactory" />
</bean>
<bean id="myRequestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="my.request.queue" />
</bean>
<bean id="messageDispatcher"
class="org.springframework.ws.soap.server.SoapMessageDispatcher">
<property name="endpointExceptionResolvers">
<list>
<bean class="util.EndpointExResolver"></bean>
</list>
</property>
</bean>

posting a JSON using Spring RestTemplate

I've converted a Java Object to json String and I am trying to post it to a rest webservice using RestTemplate and I am always getting a 500 error. The following are the details:
User createJSONUser = createUser(); // provides me the java object
//converting the javaobject to json string successfully using jackson in the next two lines
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(createJSONUser);
//creating the headers
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_JSON);
requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json")));
//setting the message converter
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
//posting the json using resttemplate
ResponseEntity<String> response = restTemplate.exchange(sandBoxURL, HttpMethod.POST, new HttpEntity<String>(jsonString, requestHeaders), String.class);
I am obtaining the resttemplate as a bean which is defined in my context-xml as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<bean id="responseMessageConverter" class = "com.uhg.iam.esso.rest.client.converters.CustomResponseConverter">
<property name="supportedMediaTypes" value="application/xml"/>
</bean>
<bean id="customErrorHandlerForEssoRestServer" class="com.uhg.iam.esso.rest.client.EssoRestClientErrorHandler"/>
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter"/>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="supportJaxbElementClass" value="true"/>
<property name="classesToBeBound">
<list>
<value>esso.schemas.core._1.Response</value>
</list>
</property>
</bean>
<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxb2Marshaller"/>
<property name="unmarshaller" ref="jaxb2Marshaller"/>
</bean>
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="prefixJson" value="false"/>
<property name="supportedMediaTypes" value="application/json"/>
</bean>
<bean id="restTemplateBean" class="org.springframework.web.client.RestTemplate">
<property name="errorHandler" ref="customErrorHandlerForEssoRestServer"/>
<property name="messageConverters">
<list>
<!-- <ref bean="marshallingHttpMessageConverter"/>
<ref bean="responseMessageConverter"/> -->
<ref bean="jsonHttpMessageConverter"/>
<ref bean="stringHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="essoRestClientDelegate" class="com.uhg.iam.esso.rest.client.EssoRestClientJSONDelegate">
<property name="restTemplate" ref="restTemplateBean"/>
</bean>
</beans>
Can someone please point out where I am making a mistake?