Spring autowiring list of components - java

I have an interface:
public interface IExternalCommandExecutor {
String[] getCommandNames();
void process(String command) throws FailedOperationException;
}
And two implementations(second is similar):
#Service
public class ExecutorImpl implements IExternalCommandExecutor {
//some code...
}
And service, in which I'm using #Autowired annotation on the list of IExternalCommandExecutor:
#Service
public class ExternalCommandsService {
#Autowired
List<IExternalCommandExecutor> commandExecutors;
// other code
}
When I'm trying to run this, I'm getting this error:
NoSuchBeanDefinitionException: No qualifying bean of type
'java.util.List<com.mpcomp.entity.system.IExternalCommandExecutor>' available:
expected at least 1 bean which qualifies as autowire candidate
Which is weird behavior for Spring. As it was mentioned in this article and in the javadoc, Spring should try to autowire all elements of IExternalCommandExecutor instead of trying to find bean of type java.util.List.
If I would change List<IExternalCommandExecutor> to IExternalCommandExecutor[], error is quite similar:
NoSuchBeanDefinitionException: No qualifying bean of type
'com.mpcomp.entity.system.IExternalCommandExecutor[]' available:
expected at least 1 bean which qualifies as autowire candidate
I'm using Spring of version 4.3.8 RELEASE. Any help will be appreciated!
Edit
Interface and service are in the core module, and implementations of interface are in 'children' module which is depends on core module. When I moved service to this 'children' module, everything works fine!

Related

Mapstruct cannot find impl

I am using mapstruct to transform a DTO into an object and vice versus and I am getting the following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.rppjs.customer.online.portal.dtos.mapper.UserMapper' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1506)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1101)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:819)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:725)
I can see that UserMapper.impl is being generated but still the above exception. My code is on github on this branch 42_RenameCodeBaseToCustomerOnlinePortal. The code is pretty simple and not many lines of code. The exception is generated as part of the RegistrationEndpointIT.java.
Please could you take a look where I am going wrong? It is using a gradle wrapper.
Additionally, I get the following exception when running Application.java:
Description:
Parameter 0 of constructor in
com.rppjs.customer.online.portal.endpoints.RegistrationEndpoint
required a bean of type
'com.rppjs.customer.online.portal.dtos.mapper.UserMapper' that could
not be found.
Action:
Consider defining a bean of type
'com.rppjs.customer.online.portal.dtos.mapper.UserMapper' in your
configuration.
Please note, Application.java is a Spring boot application.
The problem is that RegistrationEndpoint uses the mapper as constructor argument. Since it is a component Spring wants to autowire it. But neither UserMapper nor UserMapperImpl are spring beans, therefore the exceptions.
You have two options:
Remove the UserMapper constructor argument and get your mapper with Mappers.getMapper(UserMapper.class). Best practive would be to also public MAPPER instance inside your mapper (see the example here)
If you need autowired dependencies inside your mapper you can define your mapper as as spring bean as follows:
#Mapper(componentModel = "spring")
#Component
public interface UserMapper() {
//...
}

spring boot scanning and injecting external non-spring beans

What does it take, or is it even possible for Spring to scan and inject non-spring annotated classes? For example.
resource.jar
com.project.resource.ResourceInterface
com.project.resource.StandardResource <-- concrete implementation
#Singleton <--- Standard CDI annotation
public class StandardResource implements ResourceInterface{
#Override
public void something(){}
}
Now let's say I have a spring boot application which depends on resource.jar.
com.project.resource.SpringApp
#SpringBootApplication(scanBasePackages = {"com.project"})
#EnableAutoConfiguration
public class SpringApp{
... initializer
#Inject
private ResourceInterface resourceService; <--- this is not found
}
Is this supposed to work out of the box? Is this even possible? I'm using spring boot 2.0.0.RELEASE. I'm getting the following error:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'MainController': Unsatisfied dependency expressed through field 'resourceService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.project.resource.ResourceInterface' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#javax.inject.Inject()}
Thanks
For Spring framework #Singleton has no meaning, as such even if class is picked up by component scanning it's going to be ignored. In order for Spring to recognize your class you can:
Create a configuration class in com.project.resource with #Bean of
ResourceInterface and instantiate it as StandardResource.
Since you are using Spring Boot you can create Auto-configuration (which will be similar to the first option) in resource.jar. You can follow examples
from creating autoconfiguration. With this approach no changes needed in com.project.resource
After that your spring boot app will run normally

How to autowire service with implicit ExecutionContext argument

In a Scala project I work on we have an API that early on imports a global execution context like this
import scala.concurrent.ExecutionContext.Implicits.global
I later create a UserStorageService that requires said execution context. I'm attempting to introduce Spring Annotations into my application, but I'm getting stuck on how to handle the execution context. How do I autowire an implicit variable? I've tried this
class UserStorageService(
#Qualifier("userdb") val databaseConnector: DatabaseConnector
)(implicit executionContext: ExecutionContext) extends UserStorageTable {
that I'm trying to get as
private val userStorageService = appContext.getBean(classOf[UserStorageService])
resulting in
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'scala.concurrent.ExecutionContext' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
import this:
import scala.concurrent.ExecutionContext;
import scala.concurrent.ExecutionContext$;
and in your configuration(#Configuration) add this
#Bean
public ExecutionContext getExecutionContext() {
return ExecutionContext$.MODULE$.global();
}
And ExecutionContext bean will be added to the Spring context.

Bamboo ProcessService bean does not exist?

Following https://developer.atlassian.com/bamboodev/bamboo-tasks-api/executing-external-processes-using-processservice I would like to invoke some command using ProcessService bean. The injection as described in the link, does not work.
I checked the source of several other plugins at Bitbucket, but each is using the concept as described in the link.
My class:
import com.atlassian.bamboo.process.ProcessService;
public class CheckTask implements TaskType {
private final ProcessService processService;
public CheckTask(#NotNull final ProcessService processService) {
this.processService = processService;
}
However Bamboo does not find the ProcessService bean and fail with following:
(org.springframework.beans.factory.UnsatisfiedDependencyException :
Error creating bean with name 'bamboo.tasks.CheckTask': Unsatisfied
dependency expressed through constructor argument with index 0 of type
[com.atlassian.bamboo.process.ProcessService]: : No qualifying bean of
type [com.atlassian.bamboo.process.ProcessService] 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 [com.atlassian.bamboo.process.ProcessService]
found for dependency: expected at least 1 bean which qualifies as
autowire candidate for this dependency. Dependency annotations: {})
Am I missing something ?
Bamboo version: 5.13.0
AMPS version: 6.2.6
The solution in the end was quite simple, no oficial docs discuss the solution though. Hope this helps you a bit.
Finally thanks to this post I made it work: https://answers.atlassian.com/questions/33141765/testcollationservice-not-injected-into-tasktype-constructor-on-sdk-bamboo
import com.atlassian.bamboo.process.ProcessService;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
#Scanned
public class CheckTask implements TaskType {
#ComponentImport
private final ProcessService processService;
public CheckTask(#NotNull final ProcessService processService) {
this.processService = processService;
}
The rest of the project was basicaly default, as generated by atlas-create-bamboo-plugin.
Try to add in your atlassian-plugin.xml next line
<component-import key="processService"
interface="com.atlassian.bamboo.process.ProcessService"/>
That should help you

Spring #Resource Expected at least 1 bean which qualifies as autowire candidate for this dependency

I'm trying to run a web app and I'm having some issues. Basically I have a controller and a process and they both share a queue.
The controller manages the files that are uploaded to the server and it puts them in the queue. In the other side, the process takes the files in the queue and uses them for other things.
I've defined the queue as a LinkedBlockingQueue and the annotation #Resource on both of them, but when I run the app, the following exception appears:
Error creating bean with name 'csvQueueConsumerBean': Injection of resource
dependencies failed; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type [java.util.concurrent.LinkedBlockingQueue] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for this
dependency.
The code of both clases is the following:
#RestController
#RequestMapping("/upload")
public class FileUploadControllerW {
#Resource
protected LinkedBlockingQueue<QueueObject> csvQueue;
...
}
#Component
public class CsvQueueConsumerBean{
#Resource
protected LinkedBlockingQueue<QueueObject> csvQueue;
...
}
Just for the record, both classes are not on the same package.
The reason for this is because Spring context cannot wire the Bean called
csvQueueConsumerBean
You will need to initialize its LinkedBlockingQueue dependency in the Spring config file like this:
#Bean
public LinkedBlockingQueue<QueueObject> linkedBlockingQueue(){
LinkedBlockingQueue<QueueObject> blockingQueue = new LinkedBlockingQueue<QueueObject>();
// do what you need here...
return blockingQueue;
}

Categories