How custom Account Repository become a bean without any annotation ? - java

I customized the spring security for my spring boot app.
I use a custom Account Repository:
import org.springframework.data.jpa.repository.JpaRepository;
import com.boot.cut_costs.config.security.CustomUserDetails;
public interface AccountRepository extends JpaRepository<CustomUserDetails, String>{
public CustomUserDetails findByUsername(String username);
}
As you can see, I don't use any annotation for it. But in other classes, I can access it as a bean ? how is it possible ?

When you are using spring boot and your main application class in a root package above other classes then the bean classes will be scanned and detected automatically and you can look here on this.
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan.
Also, #EnableAutoConfiguration annotation implicitly defines a base
“search package” for certain items.

Check out this annotation #EnableJpaRepositories. You may be using it as a class level annotation on one of your #Configuration class.
From the docs
Annotation to enable JPA repositories. Will scan the package of the annotated configuration class for Spring Data repositories by default.
Example:
#Configuration
#EnableJpaRepositories(basePackages = {"xxx.xxx.xxx.core.dao"})
#EnableTransactionManagement
public class DatabaseConfig{
}

Related

Failing to import external jar containing bean

I'm a little new t working with Spring so any help provided would be great.
I have a SpringApplication class (annotated with #SpringBootApplication. In another class (within the same project), it contains a ServiceClass class. When the class is in the same project, it runs as expected.
When the ServiceClass is moved to an external jar, I get the following error.
Description:
Field service in
package-to-class.Comp required a
bean of type 'package-to-class.ServiceClass'
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
'package-to-class.ServiceClass' in your
configuration.
I am trying to find what I need to do to inject (#AutoWired) into my project with the above error.
By default, Spring Boot's component scanning only looks in the same package as the #SpringBootApplication and its descendants.
The approach I would suggest is using #Import to import specific beans from outside the project, or use #ComponentScan to import all beans from a package in another project.
#SpringBootApplication
#Import(ServiceClass.class)
public class SpringApplication {
// ...
}
or
#SpringBootApplication
#ComponentScan(basePackages = "com.example.mylibrary")
public class SpringApplication {
// ...
}
Okey some basic things, you have mixed up your packages a bit.
#SpringBootApplication will scan all classes in packages below the class this is annotated on. This annotation is an alias for #EnableAutoConfiguration, #Configuration and #ComponentScan means that #ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class) is not needed.
com.springdi.example // class with #SpringBootApplication annotation
|
|
|
com.springdi.example.* // Will find all #Service, #Component, #Configuration
// in subpackages below the #SpringBootApplication
// annotation
You can read more about the annotation here SpringBootApplication
Since your other annotated classes are NOT in the same package structure as the #SpringBootApplication you need to define all the places you want to scan for annotations.
#SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"})
will probably include all the packages that you want to scan through.

SPRING BOOT annotation: are they required

Are #Component, #Service and #Repository optional in Spring Boot 2?
Example If have a controller class called FirstController annotated with #Controller, #RestController and #RequestMapping. I also have service classes called FirstService and SecondService and a repository called FirstRespository.
I didn't annotate any of the class except FirstController but still my application works.
Does this mean that those stereotype annotations are not required for your app to make it work? You just need it for convention and if you need to modify behaviour like scope etc.
Thanks for answering in advance.
They are not required in order for your application to work BUT they will not be picked up by Spring on your application launch nor you will have benefits of that annotation specification
#Component - generic stereotype for any Spring-managed component
#Repository - stereotype for the persistence layer
#Service - stereotype for service layer
Any code can pass when you write your Spring application, but annotation helps Spring to understand what should be created as a bean or a component and for which use.
Consider this:
#Service
public class MyService {
private IComponent component;
#Autowired
public MyService(IComponent component) {
this.preparingService = preparingService;
}
}
In order to autowire a class implementing IComponent, you need to have that class decorated with #Service or #Component in order for Spring to inject it into MyService when MyService is itself of course injected in your controller.

Why is bean not found during Spring Boot?

I reconfigured my DAOs to a more convenient way (by using JpaRepository) instead of doing all that boilerplate code manually. But now everytime I start the Spring Application it gives me the following error:
APPLICATION FAILED TO START
Description:
Field userRepository in DAO.UserDAOService required a bean of type 'DAO.UserRepository' 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 'DAO.UserRepository' in your configuration.
Process finished with exit code 1
SOLUTION: Just create sub-packages in the same package where you have your Spring appliciation located.
EXAMPLE OF SOLUTION CAN BE FOUND HERE: 'Field required a bean of type that could not be found.' error spring restful API using mongodb
You've forgot to put an annotation on your repository class. That's why Spring cannot find that bean.
Try adding #Repository on top of your class definition.
Add #Repository annotation then bean will created and autowired in service.
import org.springframework.stereotype.Repository;
#Repository
public interface UserRepository extends JpaRepository<User , Integer>
{
}
And don't need to create bean in service
#Bean
public void setUserRepository(UserRepository userRepository)
{
this.userRepository = userRepository;
}
Make sure that you have your repository class in a sub-package of the ApplicationConfiguration class.
Annotate the repository class with #Repository.
In addition to the previous answers, the IDE can often suggests you the wrong import for the annotation of the Bean class, for example for a #Service annoted bean, be sure that you import:
import org.springframework.stereotype.Service;
and not something like:
import org.jvnet.hk2.annotations.Service

#SpringBootApplication and #ComponentScan not working together (bean configuration)

I have a multi module project but I am having a problem with my configuration.
I have a my main method in package nl.example.hots.boot
#SpringBootApplication
#EnableAutoConfiguration
#ComponentScan(basePackages = {"nl.*"})
#EntityScan("nl.*")
public class HotsApplication {
public static void main(String[] args) {
SpringApplication.run(HotsApplication.class, args);
}
In the nl.example.hots.core.* package I have the class:
#Service
#AllArgsConstructor
#Transactional(propagation = Propagation.REQUIRED)
public class MapImportService {
private MapInputModelMapper mapInputModelMapper;
private MapEntityRepository mapEntityRepository;
public void add(final MapInputModel mapInputModel) {
System.out.println(mapInputModel.getName());
mapEntityRepository.save(mapInputModelMapper.mapToEntiy(mapInputModel));
}
and:
#Component
#Mapper
public interface MapInputModelMapper {
MapInputModel mapToInputModel(final MapEntity n);
MapEntity mapToEntiy(final MapInputModel n);
}
The repository is in the package nl.example.hots.persistence.*
I get the following error when running the application:
Description:
Parameter 0 of constructor in nl.example.hots.core.dataimport.MapImportService.MapImportService required a bean of type 'nl.timonschultz.hots.core.map.mapper.MapInputModelMapper' that could not be found.
Action:
Consider defining a bean of type 'nl.example.hots.core.map.mapper.MapInputModelMapper' in your configuration.
When I remove the #EnableAutoConfiguration and #ComponentScan annotations it works. The application starts without the bean error.
In that case however my restcontroller does not work anymore:
{
"timestamp": "2018-07-18T20:48:39.414+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/maps"
}
When I remove the MapImportService class (and the bean error doesn't pop up) it works on the same url.
package nl.example.hots.api.data_import;
#RestController
#AllArgsConstructor
public class ImportController {
private static final String URL = // a url
private Reader reader;
#RequestMapping("/maps")
public String abilityStreamImport() {
reader.readStream(URL); // calls a class in nl.example.hots.core.*
return "Greetings from APP!";
}
}
I tried several different combinations and I have a different project as and example where the annotations are used together and it works right. Can somebody explain why the annotations generate the bean error when used together? And why the controller gives an error when only using #SpringBootApplication?
In my Pom.XML the boot module has a dependency on the API layer that has a dependency on the core layer that has a dependeny on the persistence layer.
I'm using mapstruct and Lombok in the project.
--- edit: repository ---
#Entity(name = "MAPS")
#Builder
#NoArgsConstructor
#AllArgsConstructor
#Getter
public class MapEntity extends HasId<Long> {
private String name;
#ElementCollection
private List<String> translations;
}
#Repository
public interface MapEntityRepository extends JpaRepository<MapEntity, Long> {
}
#MappedSuperclass
public abstract class HasId<T> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Setter
#Getter
private T id;
}
project structure:
hots-application;
- hots-api
- pom.xml
- nl.example.hots.api.dataimport.ImportController;
- hots-boot
- pom.xml
- nl.example.hots.boot.HotsApplication;
- hots-core
- pom.xml
- nl.example.hots.core.dataimport.mapImportService.MapImportService;
- nl.example.hots.core.map.mapper.MapInputModelMapper
- hots-persistence
- pom.xml
- nl.example.hots.persistence.common.HasId;
- nl.example.hots.persistence.map.MapEntity;
- nl.example.hots.persistence.map.MapEntityRepository;
pom.xml
Spring Boot will scan all the packages and sub packages starting with the package that the #SpringBootApplication annotated class is in. Your class is in nl.example.hots.boot scanning only that package. The other classes are in different, non-scanned packages.
Due to this package structure and not following the best practices you basically loose a lot of the auto configuration features (Spring Data JPA, ReST etc) and you have to resort to manually enabling/configuring that. Partially through adding additional #ComponentScan annotation, for JPA the #EntityScan annotations. But you would also need to add all the #EnableJpaRepository etc. annotations as those aren't added anymore (at least not with the right packages).
The fix is fairly easy. Move your #SpringBootApplication annotated class to the nl.example.hots package (as stated in the best practices). Remove the annotations other then #SpringBootApplication and simply start your application.
You're missing the #Autowired annotation on your #AllArgsConstructor, try:
#AllArgsConstructor(onConstructor = #__(#Autowired))
After some trial and error I managed to get it working for the most part.
I added the scanBasePackages = "nl" to the SpringBootApplication annotation.
Mapstruct did give me some trouble still however but when I removed it and made a quick mapper myself it all worked fine.
Thanks for all the help and suggestions and links to read up on! I'll keep the (bestpractice) suggestions in mind for my next project.
Below is my main class now
package nl.example.hots.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication(scanBasePackages = "nl")
#EntityScan("nl.*")
#EnableJpaRepositories("nl.*")
public class HotsApplication {
public static void main(String[] args) {
SpringApplication.run(HotsApplication.class, args);
}
}
Spring is not creating a MapInputModelMapperBean. I have never used MapStruct, but it kinda reminds me of mybatis. It looks weird to me that you annotate MapInputModelMapperBean with #Mapper and #Component. How is spring supposed to create the bean? Are you using some sort of spring-boot-mapstruct package that performs this magic?
I made a quick search and found this https://www.credera.com/blog/technology-solutions/mapping-domain-data-transfer-objects-in-spring-boot-with-mapstruct/, from which it seems like you would need something like:
#Mapper(componentModel = "spring")
public interface MapInputModelMapper
Which I guess will generate the implementation of the mapper with #Component on it or something similar.
The #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan with their default attributes.
The component scan default behaviour happens only in the same package and in its sub package. If your controllers or components are in different, dont forget to override your component scan default configurations.
Here is the sample code on how to override the default behavour.
#SpringBootApplication(scanBasePackages = "com.code")
Or you can specify multiple packages as shown below:
#SpringBootApplication(scanBasePackages = {"com.java2novice", "com.example"})
The #SpringBootApplication annotation is a convenience annotation that combines the #EnableAutoConfiguration, #Configuration and the #ComponentScan annotations in a Spring Boot application.
#EnableAutoConfiguration – This enables Spring Boot’s autoconfiguration mechanism. Auto-configuration refers to creating beans automatically by scanning the classpath.
#ComponentScan – Typically, in a Spring application, annotations like #Component, #Configuration, #Service, #Repository are specified on classes to mark them as Spring beans. The #ComponentScan annotation basically tells Spring Boot to scan the current package and its sub-packages in order to identify annotated classes and configure them as Spring beans. Thus, it designates the current package as the root package for component scanning.
You have used all these three annotations #SpringBootApplication , #EnableAutoConfiguration and #ComponentScan.
Instead use single annotation like #SpringBootApplication(scanBasePackages = "abc.def.ghi")
Here the HotsApplication class with more efficient annotation
#SpringBootApplication(scanBasePackages = "nl.example.hots")
public class HotsApplication {
public static void main(String[] args) {
SpringApplication.run(HotsApplication.class, args);
}

Scan components of different maven modules/JARs in a Spring Boot application

I have two Maven modules.
The first one, called "application", contains the spring boot Application class that just contains these lines:
package org.example.application;
#SpringBootApplication
#ComponentScan({"org.example.model", "org.example"})
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
In the same Maven module and package, org.example.application, I have a RestController that uses a Component that in turn uses the components of the other Maven module described below.
The other Maven module, called "model", contains the spring boot components (crud-repositories, entities etc). All those classes are under the same package structure as the first Maven module (org.example) but in subpackages of that, like org.example.model.entities, org.example.model.repositories etc.
So, the flow is like this:
Maven module application in package org.example:
SpringBootApplication -> RestController -> MyComponent
And the components that should be autowired in MyComponent are the ones in the model Maven module under the package org.example.model.
But when I start the application I just get the error:
***************************
APPLICATION FAILED TO START
***************************
Description:
Field myRepository in org.example.MyComponent required a bean of type 'org.example.model.repositories.MyRepository' that could not be found.
Action:
Consider defining a bean of type 'org.example.model.repositories.MyRepository' in your configuration.
org.example.model.repositories.MyRepository does exist in Maven module "model" but cannot be found by the SpringBootApplication class!
As you can see, I have tried to explicitly define the scan components to:
#ComponentScan({"org.example.model", "org.example"}) but that does not seem to help.
So what have I done wrong?
The first thing that you should wonder is : why do you declare #ComponentScan while one of the goal of #SpringBootApplication is (among other things) to enable the component scan ?
From Spring Boot documentation :
The #SpringBootApplication annotation is equivalent to using
#Configuration, #EnableAutoConfiguration and #ComponentScan with their
default attributes
Note that when on the class of your Spring Boot Application, you declare #ComponentScan to specify a value as basePackages, it overrides the basePackages used by default by #SpringBootApplication that is the current package where the class resides. So to have as base package both the package of the Spring Boot Application class and the additional packages that were missing, you have to explicitly set them.
Besides basePackages is recursive. So to enable the scan both for classes locating in the "org.example" and "org.example.model" packages, specifying "org.example" is enough as "org.example.model" is a sub-package of it.
Try that :
#SpringBootApplication(scanBasePackages={"org.example"})
Or alternatively :
#SpringBootApplication
#ComponentScan("org.example")
When specify #EnableJpaRepositories/#ComponentScan/scanBasePackages in a Spring Boot Application ?
As you design your Spring Boot application layout, your have two cases :
1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.
To summarize : if your classes annotated with Spring Bean stereotypes : #Component, #Repositories, #Repositories,... are located in the same package or a sub-package of the Spring Boot Application class, declaring only
#SpringBootApplication is all you need.
2) case (to avoid) where you don't use a package layout that provides the auto configuration of Spring Boot with zero configuration.
It generally means that you have candidate classes to scan that are not in the package (or sub-package) of your class annotated with #SpringBootApplication.
In this case, you add the scanBasePackages attribute or add #ComponentScan to specify packages to scan.
But additionally, if your repositories are not located in a package or sub-package of your class annotated with #SpringBootApplication, something else has to be declared such as : #EnableJpaRepositories(="packageWhereMyRepoAreLocated")
Here is the documentation about this part (emphasis is mine) :
80.3 Use Spring Data Repositories
Spring Data can create implementations of #Repository interfaces of
various flavors. Spring Boot handles all of that for you, as long as
those #Repositories are included in the same package (or a
sub-package) of your #EnableAutoConfiguration class.
For many applications, all you need is to put the right Spring Data
dependencies on your classpath (there is a
spring-boot-starter-data-jpa for JPA and a
spring-boot-starter-data-mongodb for Mongodb) and create some
repository interfaces to handle your #Entity objects. Examples are in
the JPA sample and the Mongodb sample.
Spring Boot tries to guess the location of your #Repository
definitions, based on the #EnableAutoConfiguration it finds. To get
more control, use the #EnableJpaRepositories annotation (from Spring
Data JPA).
Examples
1) case (to favor) where you use a package layout that provides the auto configuration of Spring Boot with zero configuration.
With a Spring Boot application declared in the org.example package, and all bean classes (Repositories included) declared in the same package or a sub-package of org.example, the following declaration is enough for the Spring Boot application :
package org.example;
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
The repositories could be located in the org.example.repository package such as :
package org.example.repository;
#Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
and
package org.example.repository;
#Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
The controllers could be located in the org.example.controller package :
package org.example.controller;
#RestController
#RequestMapping("/api/foos")
public class FooController {...}
and so for...
2) case (to avoid) where you don't use a package layout that provides the auto configuration of Spring Boot with zero configuration.
With a Spring Boot application declared in the org.example.application package, and not all bean classes (Repositories included) declared in the same package or a sub-package of org.example.application, the following declaration will be required for the Spring Boot application :
package org.example.application;
#SpringBootApplication(scanBasePackages= {
"org.example",
"org.thirdparty.repository"})
#EnableJpaRepositories("org.thirdparty.repository")
public class Application {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
}
}
And the bean classes could be as below.
The repositories that may come from an external a JAR could be located in the org.thirdparty.repository package such as :
package org.thirdparty.repository;
#Repository
public interface FooRepository extends JpaRepository<Foo, Long>, { }
and
package org.thirdparty.repository;
#Repository
public interface BarRepository extends JpaRepository<Bar, Long>, { }
The controllers could be located in the org.example.controller package :
package org.example.controller
#RestController
#RequestMapping("/api/foos")
public class FooController {...}
and so for...
Conclusion : defining the Spring Boot application in the base package of your namespace is really encouraged to make the Spring Boot configuration as simple as possible.

Categories