We are able to fetch access token using attached code snapshot but didn't find any way to set connection timeout as we do with spring restTemplate.Is there any way to set a connection timeout with OAuth2RestTemplate.
<bean id="bean" class="com.test.Provider">
<constructor-arg name="context" ref="context" />
<constructor-arg name="detail" ref="resourceDetails" />
</bean>
<bean id="context" class="org.springframework.security.oauth2.client.DefaultOAuth2ClientContext">
<constructor-arg name="accessTokenRequest" ref="request" />
</bean>
<bean id="request" class="org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest"/>
<bean id="resourceDetails" class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails"/>
A little late to the party, but in case you're wondering how to do this with springboot, this is a way:
#Bean
protected OAuth2RestTemplate oauth2RestTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(oAuthDetails());
oAuth2RestTemplate.setRequestFactory(clientHttpRequestFactory);
return oAuth2RestTemplate;
}
#Bean
protected ClientHttpRequestFactory requestFactory() {
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(10000); //timeout in milliseconds
requestFactory.setReadTimeout(10000); //timeout in milliseconds
return requestFactory;
}
Where oAuthDetails() is a method that reads the oauth configuration properties, similar to this:
#Bean
#ConfigurationProperties("path.to.your.oauth.properties.on.yml")
protected ClientCredentialsResourceDetails oAuthDetails() {
return new ClientCredentialsResourceDetails();
}
If I'm right, the way you give the connection timeout to the Spring RestTemplate as a constructor argument is through giving a ClientHttpRequestFactory as an argument to the constructor
RestTemplate(ClientHttpRequestFactory requestFactory)
Using for example the HttpComponentsClientHttpRequestFactory, one can set the connection timeout to the RestClient in XML as follows
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg name="requestFactory">
<bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="10000" />
</bean>
</constructor-arg>
</bean>
RestTemplate also offers a way to set the requestFactory property through a setter, which it inherits from InterceptingHttpAccessor, and in fact the constructor itself seems to use that setter to set the requestFactory given as constructor argument.
Thus, you can set the requestFactory for the OAuth2RestTemplate through the setter. In XML:
<bean id="oauth2RestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg name="resource" ref="resourceDetails" />
<constructor-arg name="context" ref="context" />
<property name="requestFactory">
<bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="10000" />
</bean>
</property>
</bean>
Or, in your case, you can for example give your class com.test.Provider a constructor argument requestFactory and then use that to set the request factory in the OAuth2RestTemplate as follows:
XML:
<bean id="bean" class="com.test.Provider">
<constructor-arg name="context" ref="context" />
<constructor-arg name="resourceDetails" ref="resourceDetails" />
<constructor-arg name="requestFactory">
<bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="10000" />
</bean>
</constructor-arg>
</bean>
And in your code set
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(this.resourceDetails, this.context);
restTemplate.setRequestFactory(this.requestFactory);
String tokenString = restTemplate.getAccessToken().getValue();
after setting the value of this.requestFactory in the constructor.
PS. I would prefer to create a single OAuth2RestTemplate for the entire class as a private field and reuse it in that class, unless you have a reason to create a new one for each request. You could create it in the constructor, as you are giving the context and details as constructor arguments, or then in a post-construct/init-method. Or even give it as a constructor-argument or as a property to your class in the XML, in case the context and resourceDetails are not used outside the restTemplate.
EDIT
After doing some more research, it seems that the problem might be harder than I thought. OAuth2RestTemplate uses an AccessTokenProvider to get the access tokens, by default it uses a chain of AccessTokenProviders through a instance of AccessTokenProviderChain in order to support the different types of grant types. It seems that each of these uses their own RestTemplate to send the requests to obtain the access token. Unfortunately, it seems that OAuth2RestTemplate doesn't offer a simple way to set the requestFactory of the default AccessTokenProviders' restTemplates.
So, if the solution that I proposed above is not working (which I suspect), I would use the following approach which I believe to work.
All the default AccessTokenProviders in Spring Security Oauth2 extend the class OAuth2AccessTokenSupport, which also is the class that creates the internal RestTemplate. Fortunately, this class offers a setter to set the requestFactory of the internal RestTemplate. So, one can create for example an instance of a ClientCredentialsAccessTokenProvider and give set the requestFactory through the setRequestFactory(...) method. In XML:
<bean id="clientCredentialsAccessTokenProvider class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider">
<property name="requestFactory">
<bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="10000" />
</bean>
</property>
</bean>
For some reason the OAuth2RestTemplate doesn't offer a way to access the default AccessTokenProviders, but one can set them through the setAccessTokenProvider(AccessTokenProvider accessTokenProvider) setter. To replicate the original default behaviour of the OAuth2RestTemplate, one would have to give an instance of a AccessTokenProviderChain, together with four default AccessTokenProviders and set their requestFactories. However, as you know that the accessed resource is of type ClientCredentialsResourceDetails, it suffices to set a single ClientCredentialsAccessTokenProvider in the setAccessTokenProvider(...) setter and set the requestFactory of the ClientCredentialsAccessTokenProvider.
So we would get the following code:
XML:
<bean id="bean" class="com.test.Provider">
<constructor-arg name="context" ref="context" />
<constructor-arg name="resourceDetails" ref="resourceDetails" />
<constructor-arg name="accessTokenProvider" ref="clientCredentialsAccessTokenProvider" />
</bean>
<bean id="clientCredentialsAccessTokenProvider" class="org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsAccessTokenProvider">
<property name="requestFactory">
<bean id="requestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="connectTimeout" value="2000" />
<property name="readTimeout" value="10000" />
</bean>
</property>
</bean>
And in your code, set the AccessTokenProvider:
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(this.resourceDetails, this.context);
restTemplate.setAccessTokenProvider(this.accessTokenProvider);
String tokenString = restTemplate.getAccessToken().getValue();
after setting the value of this.accessTokenProvider in the constructor. If you decide to create the OAuth2RestTemplate in the XML, you can write
<bean id="oauth2RestTemplate" class="org.springframework.security.oauth2.client.OAuth2RestTemplate">
<constructor-arg name="resource" ref="resourceDetails" />
<constructor-arg name="context" ref="context" />
<property name="accessTokenProvider" ref="clientCredentialsAccessTokenProvider" />
</bean>
where the bean "clientCredentialsAccessTokenProvider" is defined as above.
Hope that this works.
One issue with above solution is that ClientCredentialsAccessTokenProvider uses a bit enhanced requestFactory:
private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory() {
protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
super.prepareConnection(connection, httpMethod);
connection.setInstanceFollowRedirects(false);
connection.setUseCaches(false);
...
}
...
};
So in order to preserve the original functionality you should set up the same implementation of the factory.
Related
I have a test like the following
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:META-INF/spring/testDataSpringContext.xml" })
#Transactional
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#TestExecutionListeners({ DependencyInjectionTestExecutionListener.class, DirtiesContextTestExecutionListener.class,
TransactionDbUnitTestExecutionListener.class })
public class AgenceDAOTest {
#Autowired
private AgenceDAO mAgenceDAO;
#Test
#DatabaseSetup(value = "/META-INF/db-test/sampleData.xml", type = DatabaseOperation.REFRESH)
public void listAgences() {
List<AgenceVO> vListeAgences = mAgenceDAO.getAgences();
Assert.notNull(vListeAgences);
Assert.notEmpty(vListeAgences);
List<AgenceVO> vListeAgencesTrouvees = ListUtils.select(vListeAgences, new Predicate<AgenceVO>() {
public boolean evaluate(AgenceVO pAgenceVO) {
return pAgenceVO.getLibelle().startsWith("TEST_");
}
});
Assert.notNull(vListeAgencesTrouvees);
Assert.notEmpty(vListeAgencesTrouvees);
Assert.isTrue(vListeAgencesTrouvees.size() == 1);
}
}
Everything seems ok because in the log I see the following:
[TransactionalTestExecutionListener: startNewTransaction];Began transaction (1): transaction manager [org.springframework.jdbc.datasource.DataSourceTransactionManager#39d325]; rollback [true]
[DbUnitTestExecutionListener: setupOrTeardown];Executing Setup of #DatabaseTest using REFRESH on /META-INF/db-test/sampleData.xml
[AbstractTableMetaData: getDataTypeFactory];Potential problem found: The configured data type factory 'class org.dbunit.dataset.datatype.DefaultDataTypeFactory' might cause problems with the current database 'Oracle' (e.g. some datatypes may not be supported properly). In rare cases you might see this message because the list of supported database products is incomplete (list=[derby]). If so please request a java-class update via the forums.If you are using your own IDataTypeFactory extending DefaultDataTypeFactory, ensure that you override getValidDbProducts() to specify the supported database products.
[SQL: logStatement];select this_.AGC_ID as AGC1_0_0_, this_.AGC_CP as AGC2_0_0_, this_.AGC_ADR1 as AGC3_0_0_, this_.AGC_COMMUNE as AGC4_0_0_, this_.AGC_ADR2 as AGC5_0_0_, this_.AGC_LIBELLE as AGC6_0_0_, this_.AGC_MAIL as AGC7_0_0_, this_.AGC_NOM as AGC8_0_0_, this_.AGC_TEL as AGC9_0_0_ from FTN_AGENCE_AGC this_
[DbUnitTestExecutionListener: verifyExpected];Skipping #DatabaseTest expectation due to test exception class java.lang.IllegalArgumentException
[TransactionalTestExecutionListener: endTransaction];Rolled back transaction after test execution for test context [[TestContext#cdd54e testClass = AgenceDAOTest, locations = array<String>['classpath:META-INF/spring/testDataSpringContext.xml'], testInstance = com.edf.ftn.data.admin.AgenceDAOTest#16f2067, testMethod = listAgences#AgenceDAOTest, testException = java.lang.IllegalArgumentException: [Assertion failed] - this collection must not be empty: it must contain at least 1 element]]
The dbunit dataset is loaded after the transaction is created, so dataset data should be visible in select, but it is not visible. When the select is executed records in the dataset are not retrieved.
To verify if the dataset is being loaded I've tried to insert a duplicate key and an exception is launched, so I supose that de dataset is loaded correctly.
The datasource and transactionmanager configuration is:
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#${ip}:${port}:${schema}" />
<property name="username" value="${user}" />
<property name="password" value="${pass}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
The DAO is not configured as transactional, because in the application it isn't. But I have also tried to make it transactional, and the result is the same.
I do not understand why in this line:
List<AgenceVO> vListeAgences = mAgenceDAO.getAgences();
The dataset is not visible.
Solution found
I fixed the problem by using TransactionAwareDataSourceProxy
Finally I've got the following configuration for datasource:
<bean id="dbcpDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oracle:thin:#${ip}:${port}:${schema}" />
<property name="username" value="${user}" />
<property name="password" value="${pass}" />
<property name="defaultAutoCommit" value="false" />
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<constructor-arg ref="dbcpDataSource" />
</bean>
<bean id="futunoaTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
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.
HINT : My hosting tomcat system provides only 20 db connections
My working project in localhsot
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}"
p:username="${jdbc.username}" p:password="${jdbc.password}" />
This worked good in localhost, but in production it run for a while and Exception : "user has allready max no of connection".
After many google
I used c3p0
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close" >
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
This worked in localhost, but same problem in production server
Hint: I think some config in c3p0 can solve this. Please help me with you suggestion (My hosting provides only 20 connections)
Also i tried tomcat
<bean id="dataSource" class="org.apache.tomcat.jdbc.pool.DataSourceFactory">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxActive" value="20"/>
</bean>
The above tomcat code is wrong and will not work - because wrong property (I know that). How to set this for my production use(only 20 connections)
If you know how to use tomcat pool please help us.
I also used bonecp
<bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close" >
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="idleConnectionTestPeriod" value="60"/>
<property name="idleMaxAge" value="240"/>
<property name="maxConnectionsPerPartition" value="10"/>
<property name="minConnectionsPerPartition" value="5"/>
<property name="partitionCount" value="1"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="1000"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
This worked in localhost but same problem in production "user has to many connections".
I also tried apache-dbcp
As per tomcat 7 documentation - dbcp is no longer and tomcat will be bundled with pool. Even though i used dbcp and i cannot run my program. (I added only one jar and error was some class not found during project run)
As per my own idea :
I think above mentioned settings will be problem. Please help me with your suggestions. I'm not using hibernate up to now because of heavy weight. If hibernate can solve this problem please let us know.
EDITED
Currently I'm using this code. Is this code correct to my use(20 connection)
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"
p:driverClass="${jdbc.driverClassName}" p:jdbcUrl="${jdbc.url}"
p:user="${jdbc.username}" p:password="${jdbc.password}"
p:acquireIncrement="1"
p:checkoutTimeout="1"
p:idleConnectionTestPeriod="5"
p:maxIdleTime="5"
p:maxIdleTimeExcessConnections="1"
p:maxPoolSize="20" p:maxStatements="0" p:maxStatementsPerConnection="0"
p:minPoolSize="1"
p:numHelperThreads="100"
p:overrideDefaultUser="${jdbc.username}" p:overrideDefaultPassword="${jdbc.password}"
p:propertyCycle="3"
p:testConnectionOnCheckin="true"
p:unreturnedConnectionTimeout="5" />
DAO code :
#Repository
public class TutorialsDAOImpl implements TutorialsDAO {
//---
private JdbcTemplate jdbcTemplate;
private DataSource dataSource;
#Autowired
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
//---
#Override
public List<TutorialsCategory_vo> getTutorialsCategory() {
sql = "SELECT * FROM `tutorials_category` ORDER BY `slug` ASC;";
List<TutorialsCategory_vo> vo = null;
try {
vo = this.jdbcTemplate.query(sql, new Object[]{}, tutorialsCategory_mapper);
} catch (Exception e) {
log.log(Level.SEVERE, null, e);
}
return vo;
}
These are the codes i'm using. If there is any error/corrections pls correct me.
Edited (for Arun P Johny 's question)
My current project url.
I updated my current code above.
This is my final c3p0 settings:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"
p:driverClass="${jdbc.driverClassName}" p:jdbcUrl="${jdbc.url}"
p:user="${jdbc.username}" p:password="${jdbc.password}"
p:acquireIncrement="1"
p:checkoutTimeout="3000"
p:idleConnectionTestPeriod="5"
p:maxIdleTime="3"
p:maxIdleTimeExcessConnections="1"
p:maxPoolSize="20" p:maxStatements="20000" p:maxStatementsPerConnection="1000"
p:minPoolSize="1"
p:numHelperThreads="1000"
p:overrideDefaultUser="${jdbc.username}" p:overrideDefaultPassword="${jdbc.password}"
p:propertyCycle="3"
p:statementCacheNumDeferredCloseThreads="1"
p:testConnectionOnCheckin="true"
p:unreturnedConnectionTimeout="7" />
This works fine, but taking more time(1 or 2 secounds - not more than 3 secounds).
I also checked this code by shutting down mysql. My program waited up to, i start mysql. This is good. This code waits for all db connections to complete and out put correctly.
Can we make this settings even faster? Hint: my server provides only 20 connections.
If you provide a correct answer i'll make it as right answer, after checking.
I am trying to make two testcases using class org.springframework.ws.client.core.WebServiceTemplate. Both testcases are in different classes so I made two different beans for them.
On running the junit tests I got a error like that
Error creating bean with name 'testcases.TestAdminMethodsWebService':
Unsatisfied dependency expressed through bean property 'admin': : No
unique bean of type
[org.springframework.ws.client.core.WebServiceTemplate] is defined:
expected single matching bean but found 7: [admin, rules]; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
unique bean of type
[org.springframework.ws.client.core.WebServiceTemplate] is defined:
expected single matching bean but found 2: [admin, rules]
My bean is like this:
<oxm:jaxb2-marshaller id="marshaller_admin" contextPath="a.com.b" />
<bean id="admin" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="marshaller_admin" />
<property name="unmarshaller" ref="marshaller_admin" />
<property name="defaultUri"
value="http://dev05:8080/.." />
</bean>
<oxm:jaxb2-marshaller id="marshaller_rules" contextPath="r.com.b" />
<bean id="rules" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="marshaller_rules" />
<property name="unmarshaller" ref="marshaller_rules" />
<property name="defaultUri"
value="http://dev05:8080/.." />
</bean>
please tell me how to overcome with this problem or why this error occurs any help will be appreciated thank you.
Use the #Qualifier annotation to help Spring determine which bean should be injected.
public class TestClass {
#Autowired
#Qualifier("admin")
WebServiceTemplate admin;
#Autowired
#Qualifier("rules")
WebServiceTemplate rules;
// ... Rest of your class
}
Read up on the documentation here under the section Fine-tuning annotation-based autowiring with qualifiers.
Update:
You also need to change your xml bean definitions like this:
<oxm:jaxb2-marshaller id="marshaller_admin" contextPath="a.com.b" />
<bean class="org.springframework.ws.client.core.WebServiceTemplate">
<qualifier value="admin"/>
<property name="marshaller" ref="marshaller_admin" />
<property name="unmarshaller" ref="marshaller_admin" />
<property name="defaultUri"
value="http://dev05:8080/.." />
</bean>
<oxm:jaxb2-marshaller id="marshaller_rules" contextPath="r.com.b" />
<bean class="org.springframework.ws.client.core.WebServiceTemplate">
<qualifier value="rules"/>
<property name="marshaller" ref="marshaller_rules" />
<property name="unmarshaller" ref="marshaller_rules" />
<property name="defaultUri"
value="http://dev05:8080/.." />
</bean>
Note the inclusion of <qualifier> tag under each bean definition.
Hello this is the right answer
public class TestClass {
protected WebServiceOperations admin;
admin = (WebServiceOperations) getApplicationContext().getBean("admin");
protected WebServiceOperations rules;
rules = (WebServiceOperations) getApplicationContext().getBean("rules");
// ... Rest of the class
}
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>