I have following:
#SpringBootApplication(scanBasePackages = {"com.my.package","com.my.package.mylibrary"})
#EnableAsync
#EnableSwagger2
#ServletComponentScan
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
public class MySpringBootApplication {....}
This application has package com.my.package, and it also has a library dependency containing spring beans I want to autowire in this application, and those beans are in package com.my.package.mylibrary inside library.
So I have put both for scanBasePackages. But Spring is not able to find beans from the library?
Edit:
From library, I have:
package com.my.package.mylibrary.repository;
....
public interface MyRepository extends JpaRepository<..., ....> {....}
In application, I have:
package com.my.package.controller;
....
#RestController
public class MyController {....}
MySpringBootApplication resides in com.my.package.
Error:
Exception in thread "main" java.lang.NoClassDefFoundError: com/my/package/mylibrary/repository/MyRepository
at com.my.package.MySpringBootApplication.main(MySpringBootApplication.java:32)
Caused by: java.lang.ClassNotFoundException: com.my.package.mylibrary.repository.MyRepository
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
I added #EnableJpaRepositories for repository package. Now I see error related to entity MyEntity which MyRepository is based upon.
"java.lang.TypeNotPresentException: Type com.my.package.mylibrary.domain.MyEntity not present
So I added #EntityScan for "com.my.package.mylibrary.domain", but that makes application stuck infinitely.
First of all, you don't need to add scanBasePackages attribute in #SpringBootApplication as the base package is com.my.package.
If package is totally different, then you could have added it.
Spring Boot will automatically pick up the bean if the base package is same.
There is something called as separation of concerns that you should follow when you are writing code.
Update your MySpringBootApplication class to this :
#SpringBootApplication
#ServletComponentScan
public class MySpringBootApplication {....}
Create a separate config for asynchronous method execution.
#Configuration
#EnableAsync
public class AsynchronousConfig {.....}
Create a separate config class for Swagger 2.
#Configuration
#EnableSwagger2
public class SwaggerConfiguration {....}
Create separate config to exclude configuration.
#Configuration
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class})
public class ExcludeConfigurationFile {....}
Note: Spring boot auto configuration will automatically pick up these #Configuration files
This should work.
You might want to scan the packages seperately and change your JpaRepository to CrudRepository. The configuration to seperate the layer is as follow.
#SpringBootApplication(scanBasePackages = {"com.my.package.controller"})
#EnableJpaRepositories(basePackages = {"com.my.package.mylibrary.repository"})
#EntityScan(basePackages = {"com.my.package.mylibrary.domain"})
public class MySpringBootApplication {
public static void main(String[] args) {
MySpringBootApplication.run(MySpringBootApplication.class, args);
}
}
Related
I have a repository in different package than the configuration class , so I annotated it as the following with #Repostiory:
package test;
#Repository
public interface UserTest extends JpaRepository<User, Long> {
}
I have done the component scan on it and it didn't work :
package com.app;
#SpringBootApplication
#ComponentScan({"test","com.app"})
public class Application extends SpringBootServletInitializer {
}
Exception : No qualifying bean of type 'test.UserTest' available: expected at least 1 bean which qualifies as autowire candidate.
why doesn't the component scan work on repository unless I add enableJpaRepositories ? I thought componetScan is enough
Update:
as some of the answers provides solution , I'm asking about explanation not solution . The following will work without even doing component scan on "test" :
SpringBootApplication
#EnableJpaRepositories({"test","com.app"})
public class Application extends SpringBootServletInitializer{
}
Now the question why do I even need to use componentscan on #Repository when it doesn't work ? why in the documentation the #Repository is scanned by componentscan when it doesnt have effect and #EnableJpaRepostiories is enoguh?
from Spring documentation on component scan :
Indicates whether automatic detection of classes annotated with #Component #Repository, #Service, or #Controller should be enabled.
the #Repository in my case is not detected
In order to let spring knows what DataSource is related to what Repository you should define it at the #EnableJpaRepositories annotation.
Try enabling jpa repositories like below.
#SpringBootApplication
#ComponentScan({"test","com.app"})
#EnableJpaRepositories("test")
public class Application extends SpringBootServletInitializer {
}
UPDATE : Why #EnableJpaRepositories needed?
#SpringBootApplication automatically provides the features of the following annotations
#Configuration
#EnableAutoConfiguration
#ComponentScan
But if you try defining your own annotation then spring boot will not take care of internal auto configurations so this is the reason we have to enable repositories.
I have projects in which only #SpringBootApplication is enough if you are not writing your own things.
I hope you got the point.
Golden words :
If you want to get the maximum advantage of spring boot’s auto configuration feature, it is expected to put all your class packages under spring boot main application package (directly in main package or indirectly as sub packages).
I found an explanation about what I was doing wrong. The #Repository annotation with componentscan will not cause spring to implement the spring jpa repository. for the interfaces that implement crud repository enablejparepository should be used.
Now the use of #Repository with componentscan is when you have a repository class and you have your own DAO not for spring curd repo otherwise the implementation won't be created :
#Repository
public class UserTest {
public List<Object> findById(long l) {
.......
}
}
you should use your code like below as #ComponentScan always work with basepackages so your implementation should be like below.
package com.app;
#SpringBootApplication
#ComponentScan(basePackages={"test","com.app"})
#EnableJPARepositories
public class Application extends SpringBootServletInitializer {
}
I have packaged my entire entities of the application and the repository interfaces into one jar. The repositories are written with #Repository annotation:
#Repository
public interface InternalUserRepository extends JpaRepository<InternalUser, Long>{
}
I have included this jar file inside my spring boot application and trying to autowire the interface like this from a controller:
#RestController
public class AuthenticationController {
#Autowired
AuthenticationService authenticationService;
#Autowired
InternalUserRepository internalUserRepository;
#GetMapping("/")
public String home() {
return "Hello World!";
}
}
My Main app class is written like:
#SpringBootApplication
#EnableJpaRepositories
#ComponentScan("com.cdac.dao.cdacdao.*")
public class CdacAuthenticationMgntApplication {
public static void main(String[] args) {
SpringApplication.run(CdacAuthenticationMgntApplication.class, args);
}
}
The repository is not getting autowired. When I am firing up the Spring boor application I am getting the following error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field internalUserRepository in
com.cdac.user.cdacauthenticationmgnt.controller.AuthenticationController required a bean of type 'com.cdac.dao.cdacdao.repository.InternalUserRepository' that could not be found.
Action:
Consider defining a bean of type 'com.cdac.dao.cdacdao.repository.InternalUserRepository' in your configuration.
Have anyone tried similar architecture like this?
If your JPA repositories are in a different package than your Spring Boot application class, you have to specify that package on the EnableJpaRepositories annotation, not Component:
#EnableJpaRepositories("com.cdac.dao.cdacdao")
The package you specified on ComponentScan is for detecting classes as regular Spring beans, not repository interfaces.
As I remember, #ComponentScan should take a complete path to a package, so I think that your package.* does not work.
Try to use type-safe component scan instead:
// You refer to your packages of your base project and your module here.
// Choose the class so that their package is cover all child package
#SpringBootApplication(scanBasePackageClasses = {xxx. InternalUserRepository.class, xxx.CdacAuthenticationMgntApplication.class})
#EnableJpaRepositories
// No need to explicit #ComponentScan
public class CdacAuthenticationMgntApplication {
Or you can try #EnableJpaRepositories("com.cdac.dao.cdacdao")
Either way, you should pick the class in the most outer package (Spring will aslo try to find bean in sub package of those component scan packages)
Annotation #SpringBootApplication has supported all function
So we don't need config manually
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#SpringBootConfiguration
#EnableAutoConfiguration
#ComponentScan(excludeFilters = {
#Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
#Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
I am building a basic program of "hello world" in SpringBoot
Code
MyController.java
package controllers;
import org.springframework.stereotype.Controller;
#Controller
public class MyController {
public String hello() {
System.out.println("Hello World");
return "foo";
}
}
DemoApplication.java
package di.prac;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import controllers.MyController;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext ctx=SpringApplication.run(DemoApplication.class, args);
MyController m = (MyController)ctx.getBean("myController");
m.hello();
System.out.println("*******"+Arrays.asList(ctx.getBeanDefinitionNames()));
}
}
I am using eclipse and created this project from http://start.spring.io/ without any dependencies.
I learned that Spring create the bean of MyController class with name myController ,but Spring is not able to find myController bean
ERROR
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'myController' available at
org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:686)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1210)
at
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
at
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at
org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
at di.prac.DemoApplication.main(DemoApplication.java:16)
Please find and explain the error in the Project
Place your controller under sub package of di.prac like di.prac.controllers or use #ComponentScan on your controller. By default, Spring scans the current and sub packages where your main application is present. If you want to scan other packages too, then you can specify the packages in #SpringBootApplication as an argument like.
#SpringBootApplication(scanBasePackages = {"com.xyz.controllers", "com.abc.models""})
We should avoid putting the #Configuration class in the default package (i.e. by not specifying the package at all). In this case, Spring scans all the classes in all jars in a classpath. That causes errors and the application probably doesn't start.
For your controller to be available in the context of Spring, you need to define that it is managed by the Spring container. Only the #Controller annotation is not enough, it indicates only the stereotype of your bean, as well as the annotations #Repository and #Service.
In cases where the beans have these annotations and are managed by Spring, it is because their packages that the spring is scanning to search for them has been specified programmatically or per xml. In your case, you should annotate your DemoApplication class with 2 other annotations:
#Configuration - Allows access to spring context
#ComponentScan - Packages to be scanned by Spring
#Configuration
#ComponentScan (basePackages = {"controllers"})
public class DemoApplication {
public static void main(String[] args) {
ApplicationContext ctx=SpringApplication.run(DemoApplication.class, args);
MyController m = (MyController)ctx.getBean("myController");
m.hello();
System.out.println(Arrays.asList(ctx.getBeanDefinitionNames()));
}
}
Just encountered same problem, solution is simple.You just (me also) created package "controllers" on the wrong place. It should be created not in java folder but under folder with name of your project. Simple but deadly mistake. Your code is written perfectly fine.
I am pretty new to Spring Boot Application. I wanted to understand how does a spring Boot Application create beans without #Configuration class . I had a look at a sample project where there was neither #Bean definitions nor a component scan yet #Autowired provided the dependency to the class. Please have a look at the snippet below:
#RestController
public class RestController{
**#Autowired
public CertificationService certificationService;**
.
.
.
.
}
//Interface
public interface CertificationService{
public List<Certification> findAll();
}
//Implementation Class
#Transactional
#Service
public class CertificationServiceImpl{
public List<Certification> findAll(){
.
.
}
}
My limited knowledge of springs tells me that when there is a #Service annotation over a class, there has to be a #ComponentScan somewhere to create the bean. But without a component scan, how does the CertificationServiceImpl bean gets created and thereby how does the autowiring of CertificationService in RestController works here?
As said in documentation:
... The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan...
Let say you have Spring Boot app class something like:
package com.mypackage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplication.class, args);
}
}
Then all packages below of package com.mypackage will be scanned by default for Spring components. By the way, you can specify packages to scan right in #SpringBootApplication annotation, without usage of #ComponentScan. More details here.
I have this main class in my project
#SpringBootApplication
#EnableOAuth2Sso
public class App
{
public static void main(String[] args) throws Exception {
SpringApplication.run(App.class, args);
}
#Bean public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
}
As far as I know, component scan scans beans in stereotyped classes which are one of #Component, #Service, #Repository, #Controller if I am not wrong.
From spring docs
By default, classes annotated with #Component, #Repository, #Service,
#Controller, or a custom annotation that itself is annotated with
#Component are the only detected candidate components.
I cannot understand how the bean in this class is registered. As it is not a stereotyped class and no annotation is annotated with #Component it shouldn't be scanned in the first place but this code works perfectly. In fact for my use case having the bean in this class was the only way my problem was solved, but that is a different thing. Can anyone please explain this. Thanks !!
#SpringBootApplication is a meta annotation which looks like:
// Some details omitted
#SpringBootConfiguration
#EnableAutoConfiguration
public #interface SpringBootApplication { ... }
#SpringBootConfiguration is also a meta annotation:
// Other annotations
#Configuration
public #interface SpringBootConfiguration { ... }
And #Configuration is:
// Other annotations
#Component
public #interface Configuration { ... }
It works Since:
By default, classes annotated with #Component, #Repository, #Service,
#Controller, or a custom annotation that itself is annotated with
#Component are the only detected candidate components.
This is because #SpringBootApplication acts also as a #Configuration annotation.
#Configuration is used to create define beans as in xml spring configurarion files.
You can have a bean configuration class.
#Configuration
class MyConfiguration{
#bean MyBean myBean(){...};
}
o you can have a Spring configuration file
<beans>
<bean id="myBean" class="MyBean" />
</beans>
In your case you're unsing Spring configuration class as you're using #SpringBootApplication
You can see more here
http://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
http://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html
http://docs.spring.io/spring/docs/4.2.1.RELEASE/javadoc-api/org/springframework/context/annotation/Configuration.html