Spring RESTful API :: Using Traits for the #RestController methods - spring

I'm trying to set up spring to use scala traits for the REST controllers.
Let's say I need 2 resources exposed: Author and Publication.
Here's the author:
AuthorController.java
#RestController
class AuthorController extends BaseController
with ReadTrait
{
def getSuffix(): String = {
"author"
}
}
and here's the publication:
PublicationController.java
#RestController
class PublicationController extends BaseController
with ReadTrait
{
def getSuffix(): String = {
"publication"
}
}
they both use the read trait.
and the read trait I need for both:
ReadTrait.java
#RestController
trait ReadTrait {
def getSuffix(): String
#Secured(Array("ROLE_USER"))
#RequestMapping(value = Array("/{resource}"), method = Array(RequestMethod.GET))
def read(#PathVariable("resource") resource: String): Author = {
if (resource == "author") {
// ...
}
}
}
So the problem that I'm facing is that Spring blows up when those 2 classes use the same trait with this:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'publicationController' bean method
public abstract com.example.project.core.Author com.example.project.api._trait.ReadTrait.read(java.lang.String)
to {[/{resource}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'authorController' bean method
public abstract com.example.project.core.Author com.example.project.api._trait.ReadTrait.read(java.lang.String) mapped.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.example.project.Application.main(Application.java:10)
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:497)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:53)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: Ambiguous mapping found. Cannot map 'publicationController' bean method
public abstract com.example.project.core.Author com.example.project.api._trait.ReadTrait.read(java.lang.String)
to {[/{resource}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}: There is already 'authorController' bean method
public abstract com.example.project.core.Author com.example.project.api._trait.ReadTrait.read(java.lang.String) mapped.
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.registerHandlerMethod(AbstractHandlerMethodMapping.java:212)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.detectHandlerMethods(AbstractHandlerMethodMapping.java:184)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.initHandlerMethods(AbstractHandlerMethodMapping.java:144)
at org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.afterPropertiesSet(AbstractHandlerMethodMapping.java:123)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping.afterPropertiesSet(RequestMappingHandlerMapping.java:126)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 21 common frames omitted
Everything builds fine and works as expected when I remove one of the Controllers. It also builds fine but doesn't work if I remove the #RestController annotation on the ReadTrait. Is the approach I'm trying out wrong? How can I make it work?
Thanks

You are confusing Spring Boot with multiple RestController without distinctive mapping.
You have to assign different RequestMapping values for each RestController class.

Related

Spring CLI [v2.2.3.RELEASE] with MongoRepository : org.springframework.beans.factory.UnsatisfiedDependencyException

I am attempting to write a simple MongoDB app with the spring cli. I used this spring with mongodb tutorial as a base, and I am getting an an UnsatisfiedDependencyException error.
Here's my code
file: Grabs.groovy
#Grab('spring-boot-starter-data-mongodb')
class Grabs {}
file: CustomerOrder.groovy
import org.springframework.data.annotation.Id
class CustomerOrder {
#Id
String id
Date orderDate
}
file: MongoOrderRepository.groovy
import org.springframework.data.mongodb.repository.MongoRepository
interface MongoOrderRepository extends MongoRepository<CustomerOrder, String> {
CustomerOrder findById(String customerId)
}
file: OrderController.groovy
#RestController
class OrderController {
#Autowired
MongoOrderRepository orderRepository
#GetMapping("/{order}")
def listOrders(#PathVariable("order") String order) {
List<CustomerOrder> orders = orderRepository.findById(order)
return orders
}
}
when I do a spring run *, here are the errors
***************************
APPLICATION FAILED TO START
***************************
Description:
Field orderRepository in OrderController required a bean of type 'MongoOrderRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'MongoOrderRepository' in your configuration.
java.lang.reflect.InvocationTargetException
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.springframework.boot.cli.app.SpringApplicationLauncher.launch(SpringApplicationLauncher.java:68)
at org.springframework.boot.cli.command.run.SpringApplicationRunner$RunThread.run(SpringApplicationRunner.java:168)
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'orderRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'MongoOrderRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:594)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
... 6 more
I attempted to put in a #Repository in my MongoOrderRepository, since that worked for a Jdbc based implementation, but that did not work. I'm not sure how to proceed. Any help would be appreciated.
Thanks
Running example: https://github.com/thiagochagas/groovy-mongodb
1) Adjusts in your code:
Grabs:
#Grab(group='org.springframework.boot', module='spring-boot-starter-data-mongodb', version='2.2.3.RELEASE')
MongoOrderRepository (Optional adjust):
interface MongoOrderRepository extends MongoRepository<CustomerOrder, String> {
Optional<CustomerOrder> findById(String customerId)
}
OrderController (List to Optional):
#GetMapping("/{order}")
def listOrders(#PathVariable("order") String order) {
Optional<CustomerOrder> orders = orderRepository.findById(order)
return orders
}
2) Install and Running code:
./gradlew clean build
./gradlew bootRun
Accessing localhost:8080/{orderId} :

NoSuchBeanDefinitionException raised even though #Autowire and # repository # service are properly configured

My controller class:
#Controller
public class UsersController
{
#Autowired
TechRequestService techrequestservices;
#RequestMapping(value="/service_request", method=RequestMethod.POST)
public #ResponseBody Map<String,Object> SaveServiceRequest(#Valid Servicerequest servicerequest,BindingResult result){
Map<String,Object> map = new HashMap<String,Object>();
Object obj=new Object();
if(result.hasErrors())
{
for (Object object : result.getAllErrors()) {
if(object instanceof FieldError) {
FieldError fieldError = (FieldError) object;
obj= (fieldError.getDefaultMessage());
}
map.put("status","400");
map.put("message",obj);
return map;
}}
techrequestservices.save_servicerequest(servicerequest);
map.put("status","200");
map.put("message","Your record have been saved successfully");
return map;
}
}
My Service Implementation class:
#Service
public class TechRequestServiceImpl implements TechRequestService{
#Autowired
TechRequestServiceDao techrequestservicedao;
public boolean save_servicerequest(Servicerequest servicerequest) {
return techrequestservicedao.save_servicerequest(servicerequest);
}
public List<Servicerequest> list() {
// TODO Auto-generated method stub
return techrequestservicedao.list();
}
}
My DaoImpl Class:
#Repository
#Transactional
public class TechRequestServiceDaoImpl implements TechRequestService {
#Autowired
SessionFactory session;
#Override
public boolean save_servicerequest(Servicerequest servicerequest) {
// TODO Auto-generated method stub
session.getCurrentSession().saveOrUpdate(servicerequest);
return true;
}
#Override
public List<Servicerequest> list() {
return session.getCurrentSession().createQuery("from Search_type_case").list();
}
}
The request comes through ajax and the pojo variables are getting their values initialized properly as i confirmed it by placing a print statement in ever setter method of pojos. The full stack trace of the exception as follows:
SEVERE: Exception sending context initialized event to listener instance of class
[org.springframework.web.context.ContextLoaderListener]
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'usersController': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: com.servicesapi.TechRequestService
com.controllers.UsersController.techrequestservices; nested exception
is org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'techRequestServiceImpl': Injection of
autowired dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: com.daoapi.TechRequestServiceDao
com.servicesimpl.TechRequestServiceImpl.techrequestservicedao; nested
exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type [com.daoapi.TechRequestServiceDao] found for
dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
at
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at
org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
at
org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
at
org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at
org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4792)
at
org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5256)
at
org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1421)
at
org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1411)
at java.util.concurrent.FutureTask.run(Unknown Source) at
java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at
java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at
java.lang.Thread.run(Unknown Source)
Is your Component-Scan set correctly to scan packages inside a given path? Try setting the component-scan in the spring xml configuration to scan the relevant packages as follows:
<context:component-scan base-package="com.main"/>
where your dao, service and controller packages are located inside com.main. This will scan all files under com.main while checking for bean definations.
Both TechRequestServiceImpl and TechRequestServiceDaoImpl implements TechRequestService therefore there are two beans of type TechRequestService in the context, but none of type: TechRequestServiceDao.
To fix: TechRequestServiceDaoImpl should implement TechRequestServiceDao

Creating library using Spring boot and aspectj

I have created a library using spring boot and aspectj.
I have created a configuration class
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages="com.x.y")
public class LoggerConfig {
}
A class for the annotation
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface EnableHttpLogging {
}
and a class for the aspect
#Aspect
#Component
public class LoggerAspect {
#Around("execution(* *(..)) && #annotation(EnableHttpLogging)")
public Object handleController(final ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
LOG.info("controller....before ");
return proceedingJoinPoint.proceed();
}
}
An error has occured after importing a class configuration "#Import(LoggerConfig.class)" into my application and trying to run it, i have the following error:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'embeddedServletContainerCustomizerBeanPostProcessor': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error Type referred to is not an annotation type: EnableHttpLogging
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.context.support.PostProcessorRegistrationDelegate.registerBeanPostProcessors(PostProcessorRegistrationDelegate.java:240)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:697)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:526)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.olps.reassurance.cgoa.endpoint.manager.Application.main(Application.java:43)
Caused by: java.lang.IllegalArgumentException: error Type referred to is not an annotation type: EnableHttpLogging
at org.aspectj.weaver.tools.PointcutParser.parsePointcutExpression(PointcutParser.java:301)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.buildPointcutExpression(AspectJExpressionPointcut.java:207)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.checkReadyToMatch(AspectJExpressionPointcut.java:193)
at org.springframework.aop.aspectj.AspectJExpressionPointcut.getClassFilter(AspectJExpressionPointcut.java:170)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:220)
at org.springframework.aop.support.AopUtils.canApply(AopUtils.java:279)
at org.springframework.aop.support.AopUtils.findAdvisorsThatCanApply(AopUtils.java:311)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findAdvisorsThatCanApply(AbstractAdvisorAutoProxyCreator.java:118)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:88)
at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:347)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:299)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1583)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
... 14 more
You need to modify the method signature of handleController and the parameter provided inside #annotation. The example shown below should work.
#Aspect
#Component
#Slf4j
public class LoggerAspect {
#Around("execution(* *(..)) && #annotation(annotation)")
public Object handleController(
final ProceedingJoinPoint proceedingJoinPoint,
EnableHttpLogging annotation)
throws Throwable {
LOG.info("controller....before ");
return proceedingJoinPoint.proceed();
}
}

#Autowired dependency is null in Groovy class implementing a Groovy interface

I am trying to inject a property class into a Groovy based class, but the injected class is null. I do have another properties class that is being injected into a class that is implementing from Tomcat's Filter interface and that is working fine.
Here is my stacktrace when starting the Spring Boot application:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stormpathAccountService' defined in file [/Users/jfitzgerald/Projects/parsezilla-api-partner/build/classes/main/com/schoolzilla/api/application/credentials/StormpathAccountService.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.schoolzilla.api.application.credentials.StormpathAccountService]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1077)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1022)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:762)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:482)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at org.springframework.boot.SpringApplication$run.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:120)
at com.schoolzilla.api.Application.main(Application.groovy:18)
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.schoolzilla.api.application.credentials.StormpathAccountService]: Constructor threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:164)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:89)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1070)
... 20 more
Caused by: java.lang.NullPointerException
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.createGroovyObjectGetPropertySite(AbstractCallSite.java:254)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.acceptGroovyObjectGetProperty(AbstractCallSite.java:239)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at com.schoolzilla.api.application.credentials.StormpathAccountService.<init>(StormpathAccountService.groovy:37)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 22 more
And here is the code that's giving me issues:
#Service
class StormpathAccountService implements AccountService {
//This is where my problem lies
#Autowired
StormpathProperties stormpathProperties
private def logger = LogFactory.getLog(StormpathAccountService)
private def path = System.getProperty("user.home") + stormpathProperties.apiKeyLocation
//more stuff here...
}
}
Groovy interface being implemented:
interface AccountService {
def createAccount(PartnerAccount account);
def deleteAccount(PartnerAccount account);
ApiKey fetchApiKey(PartnerAccount account);
}
Properties class:
#Configuration
#ConfigurationProperties(prefix = "stormpath")
class StormpathProperties {
String apiKeyLocation
String accountUrl
}
And the property names from my application.properties file:
stormpath.apiKeyLocation
stormpath.accountUrl
And finally my main Application class:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableTransactionManagement
#EnableConfigurationProperties
class Application {
static void main(String[] args) {
SpringApplication.run Application, args
}
}
I've looked through some other suggestions such as implementing a Java based interface instead of a Groovy based interface for classloader reasons, but so far that has not worked for me. I have also tried to change the method of injection to constructor based. The class is successfully injected, but the actual properties are then null.
I've spent a few days banging my head against the keyboard here, so any further help and/or explanation why it's not working would be greatly appreciated.
Edit:
Here is the other service that is using AccountService.groovy:
#Service
#Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PartnerApplicationService {
def logger = LoggerFactory.getLogger(PartnerApplicationService)
#Autowired
PartnerApplicationRepository repository
#Autowired
CredentialsRepository credentialsRepository
#Autowired
PartnerService partnerService
#Autowired
AccountService accountService
//lots more stuff...
}
I think you didn't inject the StormpathAccountService bean into the controller or another classe which uses it, if not try with injecting it:
#Autowired
StormpathAccountService stormpathAccountService;
OR:
inject the AccountService interface in it:
#Autowired
AccountService accountService;
Well, I think I found a solution that works for me. I wound up manually including the StormpathProperties file as part of the #ComponentScan. I have no idea why this needed to be explicit where everything else woks with #ComponentScan correctly.

Spring error when parameter added to bean configuration

I am using Spring and Spring Annotations to configure service layer:
Below code works fine:
#Configuration
public class AccountServices {
#Bean
public List<String> getSourceAccountsList() { //Do something }
But as soon as I change the Bean configuration method to take the string parameter (below code), I get error.
#Configuration
public class AccountServices {
#Bean
public List<String> getSourceAccountsList(String userId) { //Do something }
The error is:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'getSourceAccountsList' defined in class path resource [net/iranet/isc/saba/services/AccountServices.class]: Unsatisfied dependency expressed through constructor argument with index 0 of type [java.lang.String]: : No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:461)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1025)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:921)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:487)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
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.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [java.lang.String] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:988)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:858)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723)
... 30 more
I think you are using #Bean in a wrong way, especially in #Service layer (and usually #Bean method doesn't have a get, but only , in your case sourceAccountsList()). Who provide the userId parameter, the web controller?
If AccountService is called from a controller you have something like (pseudo-code):
#Service
public class AccountServices {
public List<String> getAccountService(String userId) {
// Retrieve List<String> from database, or file, or somewhere else via DAO
// directly
}
}
#Controller
public class Controller {
#Autowired
private AccountsService accountService;
public void doAction(Request request) {
String userId = request.getParameter("userId");
request.putParameter("accountsList",this.accountService.getSourceAccountsList(userId));
forwardTo("/newPage.jsp", request);
}
}
Read about controller/service/repository in Spring means (Google search with a lot of resource) and from SpringSource.
After you understand layer separation you can add #Transaction management (for example) and all other feature you need.
When you use #Configuration and #Bean annotations you configure beans, parameters for methods annotated with #Bean are threated as references to another beans, so you should add bean with class String and probably name of bean "userId" - name of parameter used for autowire by name.

Resources