External Java Library issue with Autowiring and injecting bean - spring

I have created a Spring Boot application managed by Maven.
I'm retrieving an company's library from our Maven repository.
In this library, we have a service interface, not being annotated with '#Service':
public interface MyService {
//...
}
This service has only one implementation :
public class DefaultMyService implements MyService {
//...
}
This library context is managed the old Spring way (in applicationContext.xml file).
I read that normally, Spring Boot is able to find the implementation if there's only one in the scope.
When I try to run "spring-boot:run" on my project, it will fail with the following error :
No qualifying bean of type 'com.pharmagest.saml.SAMLService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I tried:
To add a #ComponentScan on the configuration class, including packages in error : #ComponentScan(basePackages={"com.mycompany.web", "com.mycompany.thelibrary.client.*", "com.mycompany.thelibrary.services.*"})
To add the bean definition in applicationContext.xml (if I add the interface it tells me it can define it, thus I heard that Spring can find the default implementation if there is only one ?)
To add library at "runtime" in projects options
To add the library as external resource not via maven
In all cases I just can maven build but can't run the project.
Do you have any advice to help me ? thanks!

Won't work as the DefaultMyService has no #Component (or #Service) annotation will not be detected.
Bean definition has to be a concrete instance so use DefaultMyService instead of the interface. Spring will not detect anything for you your understanding is wrong
and 4. Will not change anything only adding dependencies without proper 1. or 2. will do nothing.
Just add a #Bean to your configuration
#Bean
public DefaultMyService myService() {
return new DefaultMyService();
}
Or import the other libraries applicatiponContext.xml which is what you probably should do.
#ImportResource("classpath:/applicationContext.xml")
Add this next to the #SpringBootApplication.

Related

cannot Autowire a class from external jar in spring boot

Have a class A in a spring boot application. Have added a module in the pom, and i am able to import that class 'B' from that module in this class
but i am not able to autowire the same,
#EnableAutoConfiguration
class A
{
A(B b)
}
There are no compile time errors, but the application fails to start
Parameter 0 of method <> required a bean of type <> that could not be found
Tried annotating the main class with #ComponentScan({"package of class B"}) , no compile errors, but the application fails to start with same error, but with different classes.
thoughts ?
If you specify #ComponentScan with a specific package, Spring will only scan that package and subpackages for Spring beans. So if your different classes are in a different package structure, you have to add those packages as well in the annotation.

Create auto configure spring library to spring-boot application

I am creating a library which uses spring 4.3.0.One of the spring-boot application will consume this library. Currently i am using #ComponentScan in the main class of spring-boot application to scan the beans inside library instead i want to auto-configure it.So what i did is i created a configuration class inside the library and declared #ComponentScan in the configuration file.
After consuming the library in spring-boot application it is not scanning the beans inside library and throws,
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.sample.book.client.service.BookService] found for dependency [com.sample.book.client.service.BookService]: 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.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1406)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1057)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1019)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:566)
... 33 common frames omitted
How to resolve this error ? Why Spring scanning #service classes before #Configuration?
Your help should be appreciable and i will provide code-samples if needed.
It seems to me that most probable cause is that your library resides in a different package than your spring boot application (and its sub-packages). When annotating a class with #SpringBootApplication you also get #ComponentScan annotation set to its default (that is scanning components in a package where a given class resides).
Personally, I prefer to create a #Configuration annotated class in my library projects. Such class is responsible for proper library setup (declaring component scan and so on). Later, in dependent project I use an #Import annotation to import that configuration class (and corresponding beans).
I like the import. But I wanted to avoid any imports or package scan in client code.
I built my-lib (spring-boot)
by defining, Configuration in resources/META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.fanniemae.ebrms.dsrunner.DecisionServiceRunnerConfiguration
added componentScan in my configuration (my-lib)
#Configuration
#EnableConfigurationProperties(DecisionServiceRunnerProperties.class)
#ComponentScan(basePackages = { "com.xyz.dsrunner.*" })
public class DecisionServiceRunnerConfiguration {
and just included as dependency in my client spring boot application.
I guess that your config is not loaded by default from your Boot Application.
I also guess that you have not added
#EnableAutoConfiguration
to your Boot Application.
So you can try to add your config to the Annotation #EnableAutoConfiguration to be loaded by your application. Then the Configuration that you put in META-INF/spring.factories inside your library-JAR is automatically loaded.
Or you can #Import your configuration in your #SpringBootApplication class
#Import({MailServiceConfig.class, ServiceConfig.class})
can be use for enable the specific configurations;
http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html

Dynamic autowire in /src/groovy

I want to be able to include Services in my Groovy Classes in /src/groovy
I found a solution with :
myBean(MyBean) { bean ->
bean.autowire = 'byName'
}
But I dont want to make this entry in the resources.groovy for all Class, so is there a Solution to Autowire all classes in a specific folder?
I'm using grails 2.4.3
This seems to be similar to this question: Grails 2.x service injection in Groovy/src
What we use and is proposed there is to get the service via the application context:
import grails.util.Holders
...
def myService = Holders.grailsApplication.mainContext.getBean 'myService'
It's not completely auto-wired, but seems to be the best way to get services into src/groovy.
Edit: also works for Grails 3
You can make a class com.example.MyClass in src/groovy a Spring bean by adding the following to BuildConfig.groovy
grails.spring.bean.packages = ['com.example']
and annotating the class with #Component, e.g.
#Component
class MyClass {
#Value('${conf.apiVersion}')
String apiVersion
#Autowired
SomeService someService
}
As shown above, you can dependency-inject the class with the usual Spring annotations such as #Value and #Autowired. I find this a much more convenient way to register a Spring bean than modifying resources.groovy.

how Spring boot explicitly not load a class if it's not a web project?

An independent common project A which supply common configuration, inside it there is a class
#RestController
public class CustomErrorController implements ErrorController {
#Autowired
private ErrorAttributes errorAttributes;
//...
}
Now there is another project B which depend on above project A, but this is not a web project only execute some business logic then exit. So in application.properties I have this configuration:
spring.main.web_environment=false
but when run project B, it failed because this exception:
No qualifying bean of type [org.springframework.boot.autoconfigure.web.ErrorAttributes] 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)}
So how to solve this problem? Could exclude CustomErrorController in B's pom.xml or if it's not a web project could not load CustomErrorController?
spring.main.web_environment=false disable the embedded container even if it is present in your project. It does not perform black magic to prevent your classes to be instantiated.
If you are using component scan and you provide classes that require a web environment it will fail (as you just saw). Maybe you need to refactor your project in several modules and isolate the web part in a separate project?
exclude CustomErrorController class
#ComponentScan(basePackages = "com.foo",
excludeFilters = {#ComponentScan.Filter(value = ProjectAApplication.class,type = FilterType.ASSIGNABLE_TYPE),
#ComponentScan.Filter(value = CustomErrorController.class, type = FilterType.ASSIGNABLE_TYPE)})
#SpringBootApplication
public class ProjectBApplication implements CommandLineRunner {

How to Autowire repository interface from a different package using Spring Boot?

I am new to Spring Boot and want to autowire a repository from a different package in a Rest Controller. It seems that when I place the interface and implementation in a different package the actual controller the autowire seems to fail.
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.acme.repository.RawDataRepository] found for dependency:..
Controller:
package com.acme.controller;
import com.acme.repository.RawDataRepository;
// imports removed!
#RestController
#EnableAutoConfiguration
#ComponentScan("com.acme")
public class DataCollectionController {
#Autowired
private RawDataRepository repository;
// code removed!
}
I have tried to use the #ComponentScan annotation but this gives no solution.
Any idea what i am missing? Whenever i put the interface into the package in which the controller resides then all goes well.
If you have Spring Data #Repositories in a different package you have to explicitly #EnableJpaRepositories (or replace "Jpa" with your own flavour). Boot takes it's defaults from the package containing the #EnableAutoConfiguration so it might work to just move that class as well.
You have to use following two annotations
#EnableJpaRepositories(basePackages = "package-name")
#EntityScan(basePackages = "package-name")
EnableJpaRepositories will enable repository if main class is in some different package.
You need to use EntityScan as well to point to package where you have your entity beans or else it will fail with 'Bean is not of managed type' error.
Spring Boot Provides annotations for enabling Repositories.
So whenever someone uses any Repository (it can be JPARepository , CassandraReposotory) it should be enabled in Application Class itself.
Example:
#EnableCassandraRepositories("package name")
#EnableJpaRepositories("package name")
After providing the above annotations, the container takes care of injecting beans for repositories as well.

Resources