I'm trying to understand how to use a OAuth2RestTemplate object to consume my OAuth2 secured REST service (which is running under a different project and let's assume also on a different server etc...)
f.e. my rest service is:
https://localhost:8443/rest/api/user
-> Accessing this URL generates an error as I am not authenticated
To request a token I would go to:
https://localhost:8443/rest/oauth/token?grant_type=password&client_id=test&client_secret=test&username=USERNAME&password=PASSWORD
After I receive the token I can then connect to the REST API by using the following URL (example token inserted)
https://localhost:8443/rest/api/user?access_token=06
I currently tried something with the following objects:
#EnableOAuth2Client
#Configuration
class MyConfig {
#Value("${oauth.resource:https://localhost:8443}")
private String baseUrl;
#Value("${oauth.authorize:https://localhost:8443/rest/oauth/authorize}")
private String authorizeUrl;
#Value("${oauth.token:https://localhost:8443/rest/oauth/token}")
private String tokenUrl;
#Bean
protected OAuth2ProtectedResourceDetails resource() {
ResourceOwnerPasswordResourceDetails resource = new ResourceOwnerPasswordResourceDetails();
List scopes = new ArrayList<String>(2);
scopes.add("write");
scopes.add("read");
resource.setAccessTokenUri(tokenUrl);
resource.setClientId("test");
resource.setClientSecret("test");
resource.setGrantType("password");
resource.setScope(scopes);
resource.setUsername("test");
resource.setPassword("test");
return resource;
}
#Bean
public OAuth2RestOperations restTemplate() {
CloseableHttpClient httpClient = HttpClients.custom().setSSLHostnameVerifier(new NoopHostnameVerifier())
.build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
AccessTokenRequest atr = new DefaultAccessTokenRequest();
OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(atr));
AuthorizationCodeAccessTokenProvider provider = new AuthorizationCodeAccessTokenProvider();
provider.setRequestFactory(requestFactory);
restTemplate.setAccessTokenProvider(provider);
return restTemplate;
}
}
I am tried to get token in controller like below.
#Controller
public class TestController {
#Autowired
private OAuth2RestOperations restTemplate;
#RequestMapping(value="/", method= RequestMethod.GET)
public String TestForm() {
System.out.println("Token : " + restTemplate.getAccessToken().getValue());
}
}
But i got below exception
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/web] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails cannot be cast to org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails] with root cause
java.lang.ClassCastException: org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails cannot be cast to org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:190)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at com.divyshivglobalinvestor.web.controller.PersonalLoanController.PersonalLoanForm(PersonalLoanController.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:624)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:218)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:442)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1082)
at org.apache.coyote.AreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:722)bstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:623)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.Th
From some blog I found that, if we need to grant password then, instead of ResourceOwnerPasswordResourceDetails, it should be used AccessTokenRequest (which is a Map and is ephemeral). It would be great if someone can help me in getting accessToken. :)
Thanks in advance !
You should use ResourceOwnerPasswordAccessTokenProvider instead of AuthorizationCodeAccessTokenProvider in restTemplate bean
Related
Spring Boot App using 2.0.3.RELEASE of Spring Boot.
So I have REST API controller written like this:
#RestController
#RequestMapping("/root/{id}")
#Slf4j
public class RootController {
#GetMapping
public ResponseEntity<?> getXXX(
#PathVariable String id,
#RequestParam(value = "status") Status status,
#RequestParam(value = "comment") String comment,
#RequestParam(value = "other") Optional<String> other) {
log.info("Requested getXXX id={} status={} other={} comment={}", id, status, other, comment);
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
}
So the interesting part is the Optional<String> other on the above definition. I have tested the above manually via calling curl:
curl -v -X GET 'http://localhost:8080/root/ID?status=OK&comment=Comment'
which results in logging output on console like this:
...Requested getXXX id=ID status=OK other=Optional.empty comment=Comment
and using curl like this:
curl -v -X GET 'http://localhost:8080/root/ID?status=OK&comment=Comment&other=MoreOther'
which results in the following output:
Requested getXXX id=ID status=OK other=Optional[MoreOther] comment=Comment
So far so good.
But of course I would like to check this via unit tests and not manually...So I wrote a REST controller test which looks like this:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = RootController.class)
#AutoConfigureMockMvc
public class RootControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void shouldReturnNotImplemented() throws Exception {
//#formatter:off
mvc.perform(
get("/root/xyz?status={status}&comment={comment}&other={other}", Status.NOTOK, "COMMENT", Optional.<String>of("Other"))
.characterEncoding("UTF-8")
.accept(MediaType.ALL)
)
.andExpect(
status().isNotImplemented()
);
//#formatter:on
}
But unfortunately the above test fails with:
MockHttpServletRequest:
HTTP Method = GET
Request URI = /root/xyz
Parameters = {status=[OK], comment=[Comment], other=[Optional[Other]]}
Headers = {Accept=[*/*]}
Body = null
Session Attrs = {}
Handler:
Type = ...RootController
Method = public org.springframework.http.ResponseEntity<?> .getRoot(java.lang.String,Status,java.lang.String,java.util.Optional<java.lang.String>)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 500
Error message = null
Headers = {}
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
Where the exception: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException is the thing I don't understand.
The final question is: Why does the test fail but the running application does not? Does someone has a hint / idea for me?
Update 1:
I have tested also the following:
get("/root/xyz?status={status}&comment={comment}&other={other}", Status.NOTOK, "COMMENT", "Other")
and furthermore which means using only strings.
get("/root/xyz?status={status}&comment={comment}&other={other}", "NOTOK", "COMMENT", "Other")
The point that the running application works perfectly but unfortunately the test do not.
Update 2:
So after turning on debugging mode in test I got the following output: This brings me more and more into the direction that there is a bug within it..cause the parameters are always converted into String instead of Optional...and based on the parameters of get(..., Object... uriVars)
it looks like there is some problem in the code...
2018-07-16 15:50:21.029 DEBUG 16022 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /root/xyz
2018-07-16 15:50:21.031 DEBUG 16022 --- [main] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public org.springframework.http.ResponseEntity<?> de....RootController.getXXX(java.lang.String,de....Status,java.lang.String,java.util.Optional<java.lang.String>)]
2018-07-16 15:50:21.057 DEBUG 16022 --- [main] .w.s.m.m.a.ServletInvocableHandlerMethod : Failed to resolve argument 3 of type 'java.util.Optional'
org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'java.util.Optional'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Optional': no matching editors or conversion strategy found
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:127)
at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124)
at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:165)
at de...RootControllerTest.shouldReturnNotImplemented(RootControllerTest.java:35)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'java.util.Optional': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:299)
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:99)
at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:73)
at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:52)
at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:692)
at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:123)
... 50 common frames omitted
This is an issue with how you are loading the test up.
When you specify #SpringBootTest(classes = RootController.class) a class with SpringBootTest it will only load that class into the context i.e. it allows you to specify certain configurations etc. that you would want to test for some integration tests rather than using ContextConfiguration.
You can either remove the RootController and load a full test application context, effectively loading your entire application.
or just specify,
#RunWith(SpringRunner.class)
#WebMvcTest
public class RootControllerTest {
To load a slice test, which will only load the required beans to completely test the WebMVC.
working tests,
https://github.com/Flaw101/mockmvctests
Edit,
I've updated my example and introduced a second controller but only load the RootController in the RootControllerMock via #WebMvcTest(controllers = RootController.class). You can see in the logged output that it only load this controller.
2018-07-16 15:34:28.264 INFO 6176 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/root/{id}],methods=[GET]}" onto public org.springframework.http.ResponseEntity<?> com.darrenforsythe.mockmvc.RootController.getXXX(java.lang.String,java.lang.String,java.lang.String,java.util.Optional<java.lang.String>)
references,
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/autoconfigure/web/servlet/WebMvcTest.html
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests
I am trying to write test case for Repository method. In that Test case I want to test Investigator name using assertEquals(). Return type of method is set for that I use for each loop to retrieve result from set and then checked expected and actual result using assertEquals() but I am getting java.lang.ClassCastException: java.util.HashMap cannot be cast to com.spacestudy.model.Investigator
can any one please tell me what I am doing wrong in test case?
InvestigatorRepository
#Query("select new map(invest.sInvestigatorName as sInvestigatorName)"
+ " from Investigator invest")
Set<Investigator> findSinvestigatorName();
I tried Like this
#RunWith(SpringRunner.class)
#DataJpaTest
public class TestInvestigatorRepository {
#Autowired
public TestEntityManager testEm;
#Autowired
InvestigatorRepository investRepo;
#Test
public void testFindSinvestigatorName() {
Investigator invest = new Investigator();
invest.setsInvestigatorName("abc");
invest.setnInstId(60);
Investigator saveInDb = testEm.merge(invest);
Set<Investigator> getFromDb = investRepo.findSinvestigatorName();
for(Investigator result : getFromDb) {
assertEquals(saveInDb.getsInvestigatorName(),result.sInvestigatorName);
}
}
}
Stack Trace
java.lang.ClassCastException: java.util.HashMap cannot be cast to com.spacestudy.model.Investigator
at com.spacestudy.repository.TestInvestigatorRepository.testFindSinvestigatorName(TestInvestigatorRepository.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
The HQL query you specify explicitly returns a Map, but the return type specified for the method specifies Set<Investigator> which are incompatible types, hence the error.
Spring Data tries to convert the types but fails and in the end, just tries to cast the result to the desired type.
In order to fix this you need to use compatible types options are:
let your query return Investigators.
let your query return a tuple by just listing the attributes: select invest.sInvestigatorName as sInvestigatorName from Investigator invest. Spring Data should be able to map that to an Investigator although your "interesting" property names might cause some troubles.
Since you are really just return a single attribute you might as well make the method return a Set<String> and use the query given in the previous point.
I encountered an issue after upgrading our Spring Data JPA from 1.9.2 to 1.10.3.
I have the following repository:
public interface ShipmentStatisticRepository extends JpaRepository<Shipment, Long> {
...
#Query("select new de.l.b.model.dto.shipment.ShipmentStatistic(s.createdYmd, count(distinct s.oid), count(op), sum(op.price)) " +
"from Shipment s " +
"join s.orderPosition op " +
"where s.created between ?1 and ?2 " +
"group by s.createdYmd")
List<ShipmentStatistic> findPerDayBetweenCreated(Date from, Date to);
...
}
When I call this method I get the following Exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Could not instantiate Collection type: org.apache.openjpa.kernel.DelegatingResultList; nested exception is java.lang.IllegalArgumentException: Could not instantiate Collection type: org.apache.openjpa.kernel.DelegatingResultList
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384)
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:122)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:436)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy154.findPerDayBetweenCreated(Unknown Source)
at de.l.b.hazelcast.map.ShipmentStatisticPerDayMapLoader.getShipmentStatistic(ShipmentStatisticPerDayMapLoader.java:40)
at de.l.b.hazelcast.map.AbstractShipmentStatisticMapLoader.load(AbstractShipmentStatisticMapLoader.java:38)
at de.l.b.hazelcast.map.AbstractShipmentStatisticMapLoader.loadAll(AbstractShipmentStatisticMapLoader.java:48)
at com.hazelcast.map.impl.MapStoreWrapper.loadAll(MapStoreWrapper.java:143)
at com.hazelcast.map.impl.mapstore.AbstractMapDataStore.loadAll(AbstractMapDataStore.java:56)
at com.hazelcast.map.impl.mapstore.writebehind.WriteBehindStore.loadAll(WriteBehindStore.java:205)
at com.hazelcast.map.impl.recordstore.BasicRecordStoreLoader.loadAndGet(BasicRecordStoreLoader.java:170)
at com.hazelcast.map.impl.recordstore.BasicRecordStoreLoader.doBatchLoad(BasicRecordStoreLoader.java:143)
at com.hazelcast.map.impl.recordstore.BasicRecordStoreLoader.loadValuesInternal(BasicRecordStoreLoader.java:129)
at com.hazelcast.map.impl.recordstore.BasicRecordStoreLoader.access$100(BasicRecordStoreLoader.java:54)
at com.hazelcast.map.impl.recordstore.BasicRecordStoreLoader$GivenKeysLoaderTask.call(BasicRecordStoreLoader.java:112)
at com.hazelcast.util.executor.CompletableFutureTask.run(CompletableFutureTask.java:67)
at com.hazelcast.util.executor.CachedExecutorServiceDelegate$Worker.run(CachedExecutorServiceDelegate.java:212)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
at com.hazelcast.util.executor.HazelcastManagedThread.executeRun(HazelcastManagedThread.java:76)
at com.hazelcast.util.executor.HazelcastManagedThread.run(HazelcastManagedThread.java:92)
Caused by: java.lang.IllegalArgumentException: Could not instantiate Collection type: org.apache.openjpa.kernel.DelegatingResultList
at org.springframework.core.CollectionFactory.createCollection(CollectionFactory.java:208)
at org.springframework.core.CollectionFactory.createCollection(CollectionFactory.java:151)
at org.springframework.data.repository.query.ResultProcessor.processResult(ResultProcessor.java:146)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:119)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:104)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:482)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:460)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 25 more
Caused by: java.lang.InstantiationException: org.apache.openjpa.kernel.DelegatingResultList
at java.lang.Class.newInstance(Class.java:427)
at org.springframework.core.CollectionFactory.createCollection(CollectionFactory.java:204)
... 39 more
Caused by: java.lang.NoSuchMethodException: org.apache.openjpa.kernel.DelegatingResultList.<init>()
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.newInstance(Class.java:412)
... 40 more
It looks like the repository can't resolve the correct constructor to fill my projection. With version 1.9.2 everything works fine.
This is my projection class:
public class ShipmentStatistic implements Serializable {
private Date date;
private long totalParcelsSent;
private long totalPositionsSent;
private long totalValue;
public ShipmentStatistic(Date date) {
this.date = date;
this.totalPositionsSent = 0;
this.totalParcelsSent = 0;
this.totalValue = 0;
}
public ShipmentStatistic(Date date, long totalParcelsSent, long totalPositionsSent, long totalValue) {
this.date = date;
this.totalPositionsSent = totalPositionsSent;
this.totalParcelsSent = totalParcelsSent;
this.totalValue = totalValue;
}
public ShipmentStatistic add(ShipmentStatistic other) {
this.totalPositionsSent += other.totalPositionsSent;
this.totalParcelsSent += other.totalParcelsSent;
this.totalValue += other.totalValue;
return this;
}
// getter and setter
}
I made a random shot and tried to add a default constructor but without success.
I can not see my error especially the only change a made was the framework update. We use OpenJPA 2.2.2 as Persistence API by the way. I upgraded to the current version 2.4.1 but this had no effect either.
Any suggestions? May this be a bug in Spring Data JPA in combination with OpenJPA?
From stacktrace, it looks like openjpa is searching for the default constructor. Could you try adding default constructor explicitly in ShipmentStatistic.java?
JPA specification mandates the use of default no-argument constructor.
http://openjpa.apache.org/builds/1.2.3/apache-openjpa/docs/jpa_overview_pc.html#jpa_overview_pc_no_arg
I am attempting to configure Ldap authentication for a Jboss web-app. Jboss loads my module, but does not authenticate credentials that are known to be good. I should point out that my module just extends LdapExtLoginModule without adding any logic. I get the same error when defering directly to LdapExtLoginModule. The error:
PBOX000070: Password invalid/Password required
is returned when I attempt to login. I tracked the error down to a null pointer being thrown by a hashtable.put() operation in org.jboss.security.auth.spi.LdapExtLoginModule.constructInitialLdapContext. Here is the stack trace:
javax.security.auth.login.FailedLoginException: PBOX000070: Password invalid/Password required
at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:284)
at com.alstom.auth.login.ldap.CustomLdapLoginModule.login(CustomLdapLoginModule.java:164)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at javax.security.auth.login.LoginContext.invoke(LoginContext.java:762)
at javax.security.auth.login.LoginContext.access$000(LoginContext.java:203)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:690)
at javax.security.auth.login.LoginContext$4.run(LoginContext.java:688)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:687)
at javax.security.auth.login.LoginContext.login(LoginContext.java:595)
at org.springframework.security.authentication.jaas.AbstractJaasAuthenticationProvider.authenticate(AbstractJaasAuthenticationProvider.java:149)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at com.etse.security.SecureMethodAuthenticationManager.authenticate(SecureMethodAuthenticationManager.java:29)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:149)
at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:169)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:145)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:97)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:102)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:336)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:653)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:920)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at java.util.Hashtable.put(Hashtable.java:514)
at org.jboss.security.auth.spi.LdapExtLoginModule.constructInitialLdapContext(LdapExtLoginModule.java:742)
at org.jboss.security.auth.spi.LdapExtLoginModule.createLdapInitContext(LdapExtLoginModule.java:463)
at org.jboss.security.auth.spi.LdapExtLoginModule.validatePassword(LdapExtLoginModule.java:340)
at com.alstom.auth.login.ldap.CustomLdapLoginModule.validatePassword(CustomLdapLoginModule.java:152)
at org.jboss.security.auth.spi.UsernamePasswordLoginModule.login(UsernamePasswordLoginModule.java:281)
... 40 more
The function:
private InitialLdapContext constructInitialLdapContext(String dn, Object credential) throws NamingException
{
String protocol = (String)options.get(Context.SECURITY_PROTOCOL);
String providerURL = (String) options.get(Context.PROVIDER_URL);
if (providerURL == null)
providerURL = "ldap://localhost:" + ((protocol != null && protocol.equals("ssl")) ? "636" : "389");
Properties env = constructLdapContextEnvironment(providerURL, dn, credential);
return new InitialLdapContext(env, null);
}
No hashtable.put() operations there so it must come from the InitialLdapContext constructor right?
public InitialLdapContext(Hashtable<?,?> environment,Control[] connCtls) throws NamingException {
super(true); // don't initialize yet
// Clone environment since caller owns it.
Hashtable env = (environment == null)
? new Hashtable(11)
: (Hashtable)environment.clone();
// Put connect controls into environment. Copy them first since
// caller owns the array.
if (connCtls != null) {
Control[] copy = new Control[connCtls.length];
System.arraycopy(connCtls, 0, copy, 0, connCtls.length);
env.put(BIND_CONTROLS_PROPERTY, copy);
}
// set version to LDAPv3
env.put("java.naming.ldap.version", "3");
// Initialize with updated environment
init(env);
}
connCtls is null (see constructor call) so the only put operation is env.put("java.naming.ldap.version", "3") which is obviously fine.
Any idea what's going on here? Thanks.
HashTable does not allow keys to be null. Verify that none of the keys you put into Hashtable env is not null. For example, for
env.put(BIND_CONTROLS_PROPERTY, copy);
BIND_CONTROLS_PROPERTY must not be null.
Hope that helps
IMO, You have a code from another version of the LdapExtLoginModule. The correct one could be this one on GitHub.
The code there is:
private InitialLdapContext constructInitialLdapContext(String dn, Object credential) throws NamingException
{
Properties env = new Properties();
Iterator iter = options.entrySet().iterator();
while (iter.hasNext())
{
Entry entry = (Entry) iter.next();
env.put(entry.getKey(), entry.getValue()); /* this is the line 742 */
}
So there seems to be a login module option with null value. Try to check your configuration.
Please, share more details about your environment next time. It will help a lot to evaluate your problem. The most important details:
application server version
used server configuration (i.e. configuration of the security domain in this case)
I googled but can't find a solution for this. It is from Core JSF 3rd.
I did:
1) Included JSF Mojarra in Build path.
2) Included MySQL JDBC driver in Build path.
3) Copied MySQL JDBC driver to Tomcat "lib" folder and "ext" JDK folder.
4) I tested JDBC driver with a small Java app and it succeeded.
CustomerBean from corejsf source code:
public class CustomerBean {
#Resource(name="jdbc/corejsf")
private DataSource source;
public ResultSet getAll() throws SQLException {
Connection conn = source.getConnection();
try {
Statement stmt = conn.createStatement();
ResultSet result = stmt.executeQuery("SELECT * FROM Customers");
// return ResultSupport.toResult(result);
CachedRowSet crs = new com.sun.rowset.CachedRowSetImpl();
// or use an implementation from your database vendor
crs.populate(result);
return crs;
} finally {
conn.close();
}
}
}
Error:
SEVERE: Servlet.service() for servlet [Faces Servlet] in context with path [/DatabaseTest] threw exception [/index.jsp(12,3) '#{customer.all}' Error reading 'all' on type com.corejsf.CustomerBean] with root cause
java.lang.NullPointerException
at com.corejsf.CustomerBean.getAll(CustomerBean.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javax.el.BeanELResolver.getValue(BeanELResolver.java:87)
at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:67)
at com.sun.faces.el.FacesCompositeELResolver.getValue(FacesCompositeELResolver.java:72)
at org.apache.el.parser.AstValue.getValue(AstValue.java:169)
at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:189)
at org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:106)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:190)
at javax.faces.component.ComponentStateHelper.eval(ComponentStateHelper.java:178)
at javax.faces.component.UIData.getValue(UIData.java:554)
at javax.faces.component.UIData.getDataModel(UIData.java:1248)
at javax.faces.component.UIData.setRowIndex(UIData.java:447)
at com.sun.faces.renderkit.html_basic.TableRenderer.encodeBegin(TableRenderer.java:81)
at javax.faces.component.UIComponentBase.encodeBegin(UIComponentBase.java:823)
at javax.faces.component.UIData.encodeBegin(UIData.java:937)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1611)
at javax.faces.render.Renderer.encodeChildren(Renderer.java:168)
at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:848)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1613)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1616)
at com.sun.faces.application.view.JspViewHandlingStrategy.doRenderView(JspViewHandlingStrategy.java:420)
at com.sun.faces.application.view.JspViewHandlingStrategy.renderView(JspViewHandlingStrategy.java:209)
at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:126)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:127)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:313)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:563)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:399)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:317)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:204)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:182)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:311)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
You need to configure a JNDI datasource with the name jdbc/corejsf in Tomcat.
I suspect that datasource is not injected, since nothing in your class path interprets the #Resource annotation. As far as I know, #Resource is an EJB annotation, but Tomcat is no EJB container. Try looking up the datasource programatically.