I am having an issue in which a defined repository is not being correctly interpreted as a bean on server startup. The class with #SpringBootApplication is in a higher directory than the defined repository, so I cannot find why it does not configure.
#SpringBootApplication:
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
import java.util.Properties;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
System.out.println("http://localhost:8080");
}
}
Repository
package lab14.panoslab.Repositories;
import lab14.panoslab.Models.Account;
import org.apache.catalina.User;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface UserRepository extends JpaRepository<Account,Long> {
#NotFound(action = NotFoundAction.IGNORE)
List<User> findByUsername(String username);
}
Error code:
*************************** APPLICATION FAILED TO START***************************
Description:
Field userRepository in lab14.panoslab.Controllers.RegisterController
required a bean of type 'lab14.panoslab.Repositories.UserRepository'
that could not be found.
Action:
Consider defining a bean of type
'lab14.panoslab.Repositories.UserRepository' in your configuration.
Process finished with exit code 1
Are you sure that your class Account implements the interface User?
And try to remove the annotation #Repository and add annotations #EntityScan and #EnableJpaRepositories in your DemoApplication class:
#SpringBootApplication
#EntityScan({"lab14.panoslab.Models"})
#EnableJpaRepositories({"lab14.panoslab.Repositories"})
public class DemoApplication {...}
Also, I would advise you to rename all your packages into lowercase and return a value of List<Account>, not List<User>.
I did face similar issue. What I have done the mistake is, I have placed my controller/repository and other component packages outside the Main Class package. So, Spring boot not able to identify my components,
For Ex: main class package is package com.example.demo;
Controller package like, package com.example.controller;
Repository package like, package com.example.repository;
Below are the two different ways to solve this problem,
Explicitly defining my component packages in #ComponentScan, like #ComponentScan(basePackages="com.example.controller,com.example.repository") with base packages of required components.
Otherwise, You can create Controller/repository packages inside the main package. So, you no need to define #ComponentScan and all.
For ex,
main class package is package com.example.demo;
Controller package like, package com.example.demo.controller;
Repository package like, package com.example.demo.repository;
Related
I am learning spring boot, I made a simple GET endpoint but whenever I request on that endpoint I keep getting 404.
Below is my code:
Student.Controller.java
package student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.Month;
import java.util.List;
#RestController
public class StudentController {
#GetMapping("/home")
public String home(){
return "This is String";
}
}
Project Structure:
If you add #ComponentScan({"student"}) annotation on DemoApplication class it should work. You can also create your packages such as controller, service, repository ... under com.example.demo, then you don't have to add additional annotations for component scanning.
Follow this project structuring advice: https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-structuring-your-code.html
I want to use both Redis and Mongo with repository manner (I do not want to use spring cache annotations but repository methods).
I annotate the main class with the following annotations.
#EnableMongoRepositories(basePackageClass = PersistencyRepository.class)
#EnableRedisRepositories(basePackageClass = CacheRepository.class)
#SpringBootApplication
Repos
public interface PersistencyRepository extends CrudRepository<Store, String> {}
public interface CacheRepository extends MongoRepository<Store, String> {}
Now, I am getting the following error.
The bean "cacheRepository" defined in com.repository.CacheRepository defined in #EnableMongoRepositories declared on StoreApplication, could not be registered. A bean with that name has already been defined in com.repository.CacheRepository defined in #EnableRedisRepositories declared on StoreApplication and overriding is disabled.
How can I use repos of differenet databases (mongo, redis)?
You extended the wrong repository interface (MongoRepository) on CacheRepository try extending CrudRepository instead.
Also, your mongo and redis entities should be separated to different packages, usually I just went with com.my.company.entity.mongo and com.my.company.entity.redis for each.
After that, you need to update those Configuration annotations. A better package design, instead of putting all annotations on Main is putting them on a separate package, then putting those annotations there. This has an added benefit of clearly splitting each configurations for what they actually do
for example:
package com.your.company.configuration;
import com.your.company.configuration.properties.ApplicationProperties;
import com.your.company.entity.mongo.BaseDocument;
import com.your.company.entity.postgres.BaseEntity;
import com.your.company.entity.redis.BaseHash;
import com.your.company.repository.mongo.BaseMongoRepository;
import com.your.company.repository.postgres.BaseJpaRepository;
import com.your.company.repository.redis.BaseRedisRepository;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
#Configuration
#EnableConfigurationProperties(ApplicationProperties.class)
#EnableJpaRepositories(basePackageClasses = {BaseEntity.class, BaseJpaRepository.class})
#EnableMongoRepositories(basePackageClasses = {BaseDocument.class,
BaseMongoRepository.class}, repositoryFactoryBeanClass = EnhancedMongoRepositoryFactoryBean.class)
#EnableRedisRepositories(basePackageClasses = {BaseHash.class, BaseRedisRepository.class})
public class BasicConfiguration {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
The above is only an example, usually I would split them further into one class each within the same package with names that describes what they are actually configuring, for example: MongoConfiguration.java, JpaConfiguration.java, etc. Note if you decide to go with that design, you need the #Configuration annotation in each of the separate classes
I believe the main issue here is that both of your interfaces PersistencyRepository and CacheRepository are in the same package, and your configurations are both scanning the same package for Spring Data Repository interfaces, creating duplicate bean names. You should separate these repositories into their own packages.
It's important to note that basePackageClasses scans the whole package for applicable interfaces. See the docs for EnableMongoRepositories.basePackageClasses (source):
Type-safe alternative to basePackages() for specifying the packages to scan for annotated components. The package of each class specified will be scanned. Consider creating a special no-op marker class or interface in each package that serves no purpose other than being referenced by this attribute.
I'm using #TestConfiguration annotation to define bean provider for the JUnit5 test class.
A test class is annotated with:
#Import(MyTestConfiguration.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT).
package com.example;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.context.annotation.Import;
import javax.annotation.Resource;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
#Import(MyTestConfiguration.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class MyTest {
...
}
A configuration class is annotated with
#TestConfiguration.
package com.example;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.context.annotation.Bean;
#TestConfiguration
public class MyTestConfiguration {
#LocalServerPort
private int port;
...
}
I'm trying to inject local server port inside the configuration class with #LocalServerPort annotation, but get a Failed to load ApplicationContext error Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.MyTestConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'local.server.port' in value "${local.server.port}".
I was using #LocalServerPort successfully in the test class, but decided to move it along with other objects which use it to the MyTestConfiguration class to make test class more clear.
Add #Lazy annotation to the test configuration class. More info here.
From the documentation:
If this annotation is not present on a #Component or #Bean definition,
eager initialization will occur. If present and set to true, the #Bean
or #Component will not be initialized until referenced by another bean
or explicitly retrieved from the enclosing BeanFactory. If present and
set to false, the bean will be instantiated on startup by bean
factories that perform eager initialization of singletons.
I'm working on a Spring Boot project. Implementing Back-End code with the data, I've got an error.
Before working on the security, that is, when I've just done with the MemberRepository, MemberService, and MemberController, it worked well. After I worked on the security, that kind of error occurs.
I'm using IntelliJ as the IDE, and the methods were MySQL, Java, Spring Boot, Spring Security, and Maven. The OS is Mac.
This is a part of MemberRepository.java code:
package com.springboot.reserving.member;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.context.annotation.Bean;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;
#Repository
public interface MemberRepository extends CrudRepository<Member, Long> { ... }
This is a part of MemberService.java code:
package com.springboot.reserving.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
#Service
public class MemberService {
#Autowired
MemberRepository memberRepository;
...
}
This is CustomUserDetailService.java code:
package com.springboot.reserving.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Optional;
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
MemberRepository memberRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return Optional.ofNullable(memberRepo.read(username))
.filter(m -> m != null)
.map(m -> new SecurityMember(m)).get();
}
}
The error message was:
Description:
Field memberRepo in com.springboot.reserving.member.CustomUserDetailsService required a bean of type 'com.springboot.reserving.member.MemberRepository' 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 'com.springboot.reserving.member.MemberRepository' in your configuration.
What should I do to fix this error?
One possible reason is that spring doesn't create Spring Data Repository out of the interface.
In a nutshell, spring data project generates a "proxy" in runtime - an implementation of the interface that will contain all the required methods for working with the database.
In order to make is possible you should enable this proxy generation for you DAOs:
This can be done with:
#EnableJpaRepositories(basePackages = "com.springboot.reserving.member")
So make sure you have this annotation on spring boot application class.
I'm learning Spring as it seems to be a very powerful framework. I've already did many getting started guides and now I'm trying with this tutorial. In it, all classes are put in the same package, but to make it more interesting I tried using different packages according to the class (entity, controller, etc.). I was about to test it before the Testing a REST Service section but got an error building the application. This is how my project is structured:
The only difference with the classes in the tutorial is the marked ServletInitializer which comes with the initializr utility (actually I used the one that comes with STS, but it's the same). As far as I understand, it has nothing to do with the problem so the content of this class is irrelevant.
Another minor difference with the tutorial is that the Application class here is called RestServicesApplication but the content is the same.
When I try to build the application (using Gradle's bootRun instead of Maven) I got the following error message:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of method init in com.example.restservices.RestServicesApplication required a bean of type 'com.example.repository.AccountRepository' that could not be found.
Action:
Consider defining a bean of type 'com.example.repository.AccountRepository' in your configuration.
:bootRun FAILED
So I tried to annotate AccountRepository with #Bean but it gives me a compilation error saying that the annotation is disallowed for that location. Next I tried with the #Component annotation (also on BookmarkRepository) and adding #ComponentScan("com.example") in RestServicesApplication. After that the error remains but the message changed to
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.example.controller.BookmarkRestController required a bean of type 'com.example.repository.BookmarkRepository' that could not be found.
Action:
Consider defining a bean of type 'com.example.repository.BookmarkRepository' in your configuration.
:bootRun FAILED
I added #Component annotation to BookmarkRestController but the same error message remains. What am I missing here?
Thanks in advance for your answers.
Edit #1
The classes involved in the problem are the following (copied from my project, not the ones in the tutorial, although the differences are minimal):
RestServicesApplication
package com.example.restservices;
import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.example.entity.Account;
import com.example.entity.Bookmark;
import com.example.repository.AccountRepository;
import com.example.repository.BookmarkRepository;
#SpringBootApplication
#ComponentScan("com.example")
public class RestServicesApplication {
public static void main(final String[] args) {
SpringApplication.run(RestServicesApplication.class, args);
}
#Bean
CommandLineRunner init(final AccountRepository accountRepository,
final BookmarkRepository bookmarkRepository) {
return (evt) -> Arrays.asList(
"jhoeller,dsyer,pwebb,ogierke,rwinch,mfisher,mpollack,jlong".split(","))
.forEach(
a -> {
final Account account = accountRepository.save(new Account(a,
"password"));
bookmarkRepository.save(new Bookmark(account,
"http://bookmark.com/1/" + a, "A description"));
bookmarkRepository.save(new Bookmark(account,
"http://bookmark.com/2/" + a, "A description"));
});
}
}
BookmarkRestController
package com.example.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.repository.AccountRepository;
import com.example.repository.BookmarkRepository;
#RestController
#RequestMapping("/{userId}/bookmarks")
public class BookmarkRestController {
private final BookmarkRepository bookmarkRepository;
private final AccountRepository accountRepository;
#Autowired
public BookmarkRestController(final BookmarkRepository bookmarkRepository,
final AccountRepository accountRepository) {
this.bookmarkRepository = bookmarkRepository;
this.accountRepository = accountRepository;
}
// #RequestMapping methods...
}
AccountRepository
package com.example.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import com.example.entity.Account;
#Component
public interface AccountRepository extends JpaRepository<Account, Long> {
Optional<Account> findByUsername(String username);
}
BookmarkRepository
package com.example.repository;
import java.util.Collection;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import com.example.entity.Bookmark;
#Component
public interface BookmarkRepository extends JpaRepository<Bookmark, Long> {
Collection<Bookmark> findByAccountUsername(String username);
}
Note: I added the imports so you can see where the classes and annotations come from
Edit #2
I tried another thing: I refactored my Project to fit the tutorial and I put everithing in the same package (com.example.bookmarks) and removed the extra annotations. The Project compiles but when I run the Project I get a 404 HTTP status when trying to accesss a REST service. I'm still interested in make it run with my original structure but I want to let you know that this refactoring makes the Project work.
To have Spring create a bean that implements JpaRepository interface, you need to use Spring JPA namespace and activate the repository support using the appropriate element. In xml:
<jpa:repositories base-package="com.example.repository" />
In annotation:
#EnableJpaRepositories
See this docs
This scans all packages below com.example.repository for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of SimpleJpaRepository.
I think you have to create package again. You packing looking not right. Recreate your package