Spring JPA Repository instance not created - spring

I followed the example that the Spring organization provides here for Spring Data JPA.
This is my repository interface:
public interface CustomerRepository extends CrudRepository<Customer, Long> {
List<Customer> findByLastName(String lastName);
}
And this is a snippet of my Application class:
#Configuration
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class);
CustomerRepository repository = context.getBean(CustomerRepository.class);
I get the following error :
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.CustomerRepository] is defined
I tried adding a #Repository annotation to CustimerRespository and the #ComponentScan annotation to the Application class, but result is the same.

I had the same problem and #EnableAutoConfiguration solved it.
If it doesn't work automatically, try disabling JpaRepositoriesAutoConfiguration and explicitly specify the repositories base package:
#EnableAutoConfiguration(exclude = {
JpaRepositoriesAutoConfiguration.class
}
#EnableJpaRepositories(basePackages = {"com.project.app.repositories"})
Good luck.

Maybe try adding on your configuration class
#EnableJpaRepositories
#EnableConfigurationProperties()
#EntityScan({"com.project.app.entities" })

try to add #EnableJpaRepositories and #ComponentScan annotations in Application class to see if adding them solve your problem.
If still it doesn't work, add #Configuration in your CustomerRepository interface and then in Application class add #Import(CustomerRepository .class).
let me know if works.

Related

Spring boot #Inject proxy resolves to null

I'm refactoring an existing application to use Spring Boot. The issues I've faced here are generally of the type "why is this not working anymore".
I have three packages
- nl.myproject.boot
- nl.myproject
- nl.myproject.rest
My current problem is that all #Services that I #Inject in a #RESTController resolve to null when a method is called on them.
The service and dao are part of the nl.myproject package and the reason it's not nl.myproject.core is a legacy issue.
A related issue is that my #Configuration components don't seem to be loaded through #ComponentScan and I have to import them manually. I also had to exclude Test configuration to prevent Test configs from being loaded, which also seemed weird.
Internal calls from the service layer during start up, such as data preparation works normally. Any such manager is also #Injected. This is just to say that any of the typical injection mistakes such as manual instantiation or injecting a class instead of an interface don't apply.
I'd also be grateful for debugging tips. My Java has gotten a little rusty.
#EnableAutoConfiguration
#ComponentScan(basePackages= {
"nl.myproject",
"nl.myproject.boot",
"nl.myproject.dao",
"nl.myproject.service",
"nl.myproject.webapp"},
excludeFilters= {
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*Test.*"}),
#ComponentScan.Filter(type=FilterType.REGEX,pattern={".*AppConfig"})
}
)
#Configuration
#EnableConfigurationProperties
#Import({
JPAConfig.class,
RestConfig.class,
BootConfig.class
})
public class Startup {
public static void main(String[] args) throws Exception {
SpringApplication.run(Startup.class, args);
}
}
#RestController
#RequestMapping(value="/json/tags")
public class JsonTagController extends JsonBaseController {
#Inject
TagManager tagMgr;
public interface TagManager extends BaseManager<Tag,Long> {
[...]
}
#Service("tagManager")
public class TagManagerImpl extends BaseManagerImpl<Tag, Long> implements
TagManager {
#Inject
TagDao dao;
[...]
#Inject is a annotation specified by JSR-330 (standard) whereas #Autowired is annotation specified by Spring.
They just do the same dependency injection. You can both of them in the same code.
Just the modification (separation of the concerns) you need :
public interface TagManager {
[...]
}
#Service
public class TagManagerImpl implements TagManager {
#Inject
private TagDao dao;
// inject that service rather than extending
#Inject
private BaseManager<Tag,Long> baseManager;
}
public interface BaseManager<Tag,Long> {
[...]
}
#Service
public class BaseManagerImpl<Tag,Long> implements BaseManager<Tag,Long> {
....
}
Just one thing you do for checking, just modify to basePackages= {"nl.myproject"} - just provide only base package, that's enough for spring to scan the components in every package.
Hope this may help :)

Inject CRUD Repository in Spring

I can't Inject CRUD Repository in Spring.
Repository
#Repository
public interface EntityRepository extends CrudRepository<entity,Long>{
}
#Autowired EntityRepository eR
Error:
.. Required a Bean of Type EntityRepository that could not be found
Consider defining a bean of type 'EntityRepository' in your configuration.
My main
#SpringBootApplication
#ComponentScan({"de.xyz.*"})
#EntityScan("de.xyz.entities")
#EnableJpaRepositories("de.xyz.*")
//#EnableEurekaClient
public class Application extends SpringBootServletInitializer {
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
Another way of doing this is using the basePackages field; which is a field inside ComponentScan annotation.
#ComponentScan(basePackages = {"de.xyz.repository"})
public class Application extends SpringBootServletInitializer {
//
}
Step1 :
Try to include both the classes in the same package. This way you can narrow down the issue of component scanning. Remove all other annotations and keep only #SpringBootApplication
Note :
By default spring loads all the classes under the package of Application Class.
Step2 : See your dependencies, verify you have included the dependencies for JPA repositories.
Step3 : Post the GIT Hub link of the code, so that it can be looked further.
Otherwise add all the packages inside the component scan annotation , Like below.
#ComponentScan({ "a.b.c", "a.b.c.dao" })
As you have mentioned there is a configuration class which is creating the beans, try to include that class package in the same package or include it in component scan.
Hope this help.

Spring: What happens when we move #ComponentScan to another class in the package?

I have the following classes:
#ComponentScan
public class CDPlayerConfig {
#Autowired
private static CompactDisc cd;
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(CDPlayerConfig.class);
CompactDisc cd = context.getBean(CompactDisc.class);
System.out.println(cd);
}
}
public interface CompactDisc {
void play();
}
#Component
public class SgtPeppers implements CompactDisc {
public void play() {
System.out.println("play song....");
}
}
When I run the class CDPlayerConfig, the program runs successfully. However, if I remove the ComponentScan annotation to CompactDisc interface or SgtPeppers I get the following error:
Exception in thread "main"
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'CompactDisc' available
I think that ComponentScan annotation marks the package where Spring looks for beans. CDPlayerConfig, CompactDisc and SgtPeppers are all placed in the same package, so allegedly moving ComponentScan annotation from one class to another should not make a difference.
If so, why do I get an error?
For #ComponentScan to work you have to "tell" spring where to search, or it must find it with help of other, already loaded, #ComponentScan annotated class (your class must be then annotated also with #Component, #Configuration etc. so it could be found).
In your case, you register application context in the first line of main method - you have specified there to load CDPlayerConfig.class which is #ComponentScan annotated so now spring can automatically find other beans in the package:
ApplicationContext context =
new AnnotationConfigApplicationContext(CDPlayerConfig.class);
If you want to move #ComponentScan to another class, you have to change class registered in AnnotationConfigApplicationContext to some #ComponentScan annotated class:
SgtPeppers:
#Component
#ComponentScan
public class SgtPeppers implements CompactDisc {
(...)
Main in CDPlayerConfig:
ApplicationContext context =
new AnnotationConfigApplicationContext(SgtPeppers.class);
Note you should register context from concrete classes (not interfaces).
Also, above sample would work even without #ComponentScan annotation on SgtPeppers, but then beans defined in other classes from the package wouldn't be found.

Error while exluding MongoDataAutoConfiguration

I've tried to exclude mongoDB autoconfiguration from a spring-boot project but i keep having that error:
Method mvcConversionService in org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport required a bean named 'mongoTemplate' that could not be found.
Configuration:
#SpringBootApplication
#EnableAutoConfiguration(exclude = {MongoDataAutoConfiguration.class})
public class ChromeDataCoreApplication {
public static void main(String[] args) {
SpringApplication.run(ChromeDataCoreApplication.class, args);
}
}
Any help?
Thanks.
I found that in my case I had an interface that was annotated with #Repository and even though nothing depended on it Spring Boot created it anyway and tried to connect to the Mongo database.
WebMvcConfigurerComposite#addFormatters tries to add HateoasAwareSpringDataWebConfiguration which, in turn, requires the mongoTemplate bean. To fix this I was able to put an annotation on my repository interface:
#ConditionalOnProperty(name = "mongo.enabled", havingValue = "true")
To remove the HateoasAwareSpringWebConfiguration bean from the list of delegates used in addFormatters the following can be added to your #SpringBootApplication:
#SpringBootApplication(exclude = {org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration.class})
Of course I also included the two classes for Mongo auto configuration:
#SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class, SpringDataWebAutoConfiguration.class})
I should note that once the #ConditionalOnProperty annotation was added to the repository interface the SpringDataWebAutoConfiguration.class was no longer required.

Spring Data - MongoDB - JUnit test

I would have a question concerning Spring Data - MongoDB and JUnit test.
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = { UserRepository.class, User.class })
public class MyJUnitTest {
The UserRepository looks like this:
#Repository
public interface UserRepository extends MongoRepository<User, String> {
User findByUsername(final String username);
}
I get the following Exception:
Failed to instantiate [... .repository.UserRepository]: Specified class is an interface
My question now would be, how to do it, that UserRepository is instantiate although there is no implementation class because Spring Data does the implementation by its own? If I do not mark USerRepository with #Repository than Spring does not create a bean object
[EDIT]
I have tried the example of the link you posted and it works fine if I run the application over the main- method.
Then I tried to implement a test class but in this case I get the same exception:
Error creating bean with name 'hello.test.TestClass': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private hello.CustomerRepository hello.test.TestClass.repository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [hello.CustomerRepository] 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)}
My test class looks like this in src/test/java/hello/test (hello.test is the package):
#ComponentScan("hello")
#EnableMongoRepositories(basePackages = "hello")
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = { CustomerRepository.class, Customer.class })
public class TestClass {
#Autowired
private CustomerRepository repository;
#Test
public void testMethod() {
System.out.println("repositoryd: " + repository);
}
}
and my CustomerRepository looks like this (with #Configuration annotation):
#Configuration
public interface CustomerRepository extends MongoRepository<Customer, String> {
public Customer findByFirstName(String firstName);
public List<Customer> findByLastName(String lastName);
}
Actually I don't know which annotations I need in order to get the test running - Maybe you would have another suggestion in order that I can solve this issue.
For Spring Boot 1.5.8.RELEASE
You can use #SpringBootTest to bootstrap all you spring configurations.
Your test will look like
#RunWith(SpringRunner.class)
#SpringBootTest
public class SomeRepositoryTests {
#Autowired
private SomeRepository someRepository;
#Test
public void someTest() {
someRepository.someMethod(...);
// assertions
}
}
Of course you want to use embedded mongodb for test so add
for Maven
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<scope>test</scope>
</dependency>
for Gradle
testCompile('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
Your repo CustomerRepository doesn't require #Configuration or #Repository annotations. Spring will do it for you as you extends base Repository classes.
To setup Mongo Repositories you need to extend ApplicationContext with the following annotations.
#Configuration
#EnableAutoConfiguration // create MongoTemplate and MongoOperations
#EnableMongoRepositories(basePackages = "hello.test") // Create your repos
public class ApplicationConfig {
}
You also would like to use in-memory database for you unit/integration tests so them won't alter productions database.
To enable it just add the following dependency:
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.50.2</version>
<scope>runtime</scope>
</dependency>
Finally, configure you test class with the ApplicationContext
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ApplicationConfig.class)
public class MyJUnitTest {
// Test cases ...
}
Within #SpringApplicationConfiguration you need to point to a configuration class. Neither UserRepository nor User probably are one I assume.
To get started with both Spring and Spring Data MongoDB fundamentals, be sure to check out this getting started guide.
If using junit 5 and you want to start up spring in the most lightweight way possible you will need the following annotations on your IntegrationTest class
#DataMongoTest
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {MyMongoService.class})
#EnableMongoRepositories(basePackageClasses = MyRepository.class)
public class MyMongoIntegrationTest {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private MyRepository myRepository;
#Autowired
private MyMongoService myMongoService; <-- Assuming this injects MyRepository
}

Resources