Spring data repository not found at compile time - spring

I am trying to use Spring data and repositories in a Spring Boot application, but I have an error when compiling the project.
Here is my Entity :
package fr.investstore.model;
import javax.persistence.Id;
...
#Entity
public class CrowdOperation {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public Long id;
#Enumerated(EnumType.STRING)
public RepaymentType repaymentType;
...
}
And the corresponding Repository:
package fr.investstore.repositories;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import fr.investstore.model.CrowdOperation;
public interface CrowdOperationRepository extends CrudRepository<CrowdOperation, Long> {
}
I use it in a WS controller, generating a repository through the Autowired annotation:
package fr.investstore.ws;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMapping;
...
#Controller
#EnableAutoConfiguration
public class SampleController {
#Autowired
private CrowdOperationRepository crowdOperationRepository;
#RequestMapping(path = "/", method = RequestMethod.GET)
#ResponseBody
public String getOperations(#RequestParam(required=true, defaultValue="Stranger") String name) {
crowdOperationRepository.save(new CrowdOperation());
return "Hello " + name;
}
}
And the code of the application:
package fr.investstore;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import fr.investstore.ws.SampleController;
#SpringBootApplication
public class InvestStoreApplication {
public static void main(String[] args) {
SpringApplication.run(SampleController.class, args);
}
}
But when compiling the project I get:
APPLICATION FAILED TO START
Description: Field crowdOperationRepository in
fr.investstore.ws.SampleController required a bean of type
'fr.investstore.repositories.CrowdOperationRepository' that could not
be found.
Action: Consider defining a bean of type
'fr.investstore.repositories.CrowdOperationRepository' in your
configuration.
Woudn't Spring automatically generate a bean for the repository through the interface?
How can I resolve this?
EDIT: I also tried to put the Repository annotation (from org.springframework.stereotype.Repository) onto CrowdOperationRepository, but I got the same error

While creating a spring-boot application, we need to keep some point in our mind like
Always keep main class (class with `#SpringBootApplication annotation) on the top level package and other classes should lie under sub-packages.
Always mark your bean classes with proper annotation e.g. all repositories should be marked by #Repository annotation, all service implementation classes should be marked with #Service, other component classes should be marked by #Component, class which defines our beans should be marked as #Configuration
Enable the feature which you are using e.g. #EnableJpaRepositories, #EnableTransactionManagement, #EnableJpaAuditing, these annotations also provides functionality which let us define which package spring needs to scan.
So in your case, you need to mark InvestStoreApplication class with #EnableJpaRepositories annotation and CrowdOperationRepository with #Repository.

you have to tell your spring boot application to load JPA repositories.
copy this one to your application class
it will auto-scan your JPA repository and load it in your spring container even if you do not define your interface with #Repository it will wire that bean in your dependent class.
#EnableJpaRepositories(basePackages = { "fr.investstore.repositories" })

Thank to #JBNizet for his comment, that made it working.
I create this answer since he did not:
Replace SpringApplication.run(SampleController.class, args); with SpringApplication.run(InvestStoreApplication.class, args);. And remove the useless #EnableAutoConfiguration on your controller.

Annotating your entity class as shown as spring hint below to allow spring get a valid repository bean
Spring Data JPA - Could not safely identify store assignment for repository candidate interface com.xxxxx.xxxxRepository.
If you want this repository to be a JPA repository, consider annotating your entities with one of these annotations: javax.persistence.Entity, javax.persistence.MappedSuperclass (preferred),
or consider extending one of the following types with your repository: org.springframework.data.jpa.repository.JpaRepository.
2022-05-06 12:32:12.623 [ restartedMain] INFO [.RepositoryConfigurationDelegate:201 ] - Finished Spring Data repository scanning in 3 ms. Found 0 JPA repository interfaces.

Related

spring-boot-starter-jdbc DAO repository object not injected in working legacy webservice

I am new in the spring/boot word and have a working JAX-WS based web-service declared in a springboot project. It is started and configured via web.xml and sun-jaxws.xml. So, no beans included there only endpoints declarations and servlet definitions and mappings.
I just now want to save the items i get in the webservice into the mysql database using spring-boot-starter-jdbc which is not working:
I can't achieve this as the repository is not injected in the webservice implementation.
Followed all steps in other question, but not achieving this!
Normally declaration of the datasource parameters in application.properties and annotating #webservice and #Repository would suffice to get the injection of the repository working in the webservice class. What am i missing ?
Here details of the steps I followed:
the webservice implementation is a package X and i created a #SpringBootApplication in order to use a mysql datasource declared in application.properties.
So i annotated the webservice as a #Component and the data access repository with #Repository and #Component
parent version: spring-boot-starter-parent : 1.5.10.RELEASE
webservice service implementation:
BServiceManager.java
package X;
....
#Component
#WebService(name = "***",***)
#BindingType("http://schemas.xmlsoap.org/wsdl/soap/http")
#XmlSeeAlso({
packagesxxx.class,
....
})
public class BServiceManager
implements xxxxx
{
....
#Autowired
private ItemRepository irepo;
....
#WebMethod(**)
#WebResult(***)
public ResponseDataInfo sendInfo( ){
....
trepo.saveitem(item)
....
}
}
ItemRepository.java
package Y.Z;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
#Component
#Repository
public class ItemRepository {
#Autowired
private JdbcTemplate jdbcTemplate ;
....
public boolean saveitem(Item item) {
....
}
}
Item.java
package Y.Z;
public class Item {
....
}
GetItemsApplication
package Y;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
//#ComponentScan(basePackages={"Y","Y.Z","X"})
#SpringBootApplication
public class GetItemsApplication {
....
public static void main(String[] args) {
SpringApplication.run(GetItemsApplication.class, args);
log.info("--Spring Boot inits done--");
}
}
application.properties
spring.data.jpa.repositories.enabled=false
spring.data.jdbc.repositories.enabled=true
# MySQL properties
spring.datasource.url=****
spring.datasource.username=****
spring.datasource.password=****
....
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
logging.level.org.springframework.jdbc.core.JdbcTemplate=debug
NB: even having datasource bean is not helping :
File: DataSourceConfig.java
package Y.Z;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
//#EnableJdbcRepositories for Spring
#Configuration
public class MDataSourceConfig {
#Bean
public DataSource dataSource() {
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
return dataSourceBuilder.build();
}
#Bean
public JdbcTemplate getJdbcTemplate() {
return new JdbcTemplate(dataSource());
}
}
Your Webservice doesn't seem to get created by Spring.
Therefore Spring has no control over its dependencies, so you have to get the dependency programmatically.
There are many ways to do this.
Easy but not very elegant and uses global variables which might cause problems, especially with tests: https://stackoverflow.com/a/18486178/66686
More elegant but requires weaving Spring autowiring using #Configurable

#Autowired should not work without #RunWith(SpringRunner.class) but does

Here is a unit testing class for a java spring data repository layer.
I have a spring data repository layer in which the annotation #Autowired is used to inject TestEntityManager type object (belongs to spring data package).
The autowiring works whitout adding #RunWith(SpringRunner.class) annotation !
So what is the problem ? Well, I think that injection should not be possible whitout adding #RunWith(SpringRunner.class) annotation to the class : it should not work without it theorically.
How is it possible ? Does someone have any answer ?
>>>> view complete spring boot app code on github available here
Someone else have had the opposite problem in stackoverflow :
Someone else have had the opposite problem : see link here
Here is my strange bloc of code that amazingly that works :
package org.loiz.demo;
import org.assertj.core.api.BDDAssertions;
import org.junit.Assert;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test ;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Order ;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import demo.LoizBootSpringDemoApplication;
import demo.crepository.UserRepositoryInterface;
import demo.dmodel.User;
import demo.helper.helperUtils;
//Test de la couche de persistence
//#RunWith(SpringRunner.class)
#DataJpaTest
#ContextConfiguration(classes = { LoizBootSpringDemoApplication.class})
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
#SuppressWarnings("unused")
public class LoizPersistenceTest
{
#Autowired
private TestEntityManager testEntityManager;
#Autowired
private UserRepositoryInterface repository;
private static Long idStub ;
#Test
#Order(1)
#Rollback(false)
#DisplayName("Test de sauvegarde d\'un user \"prenom21 Nom21\"")
public void saveShouldMapCorrectly() throws Exception {
User userStub = new User("prenom21", "Nom21");
User UserSaved = this.testEntityManager.persistFlushFind(userStub);
BDDAssertions.then(UserSaved.getId()).isNotNull();
idStub = UserSaved.getId() ;
User UserRead = this.testEntityManager.find(User.class, idStub) ;
BDDAssertions.then(UserSaved.getFirstName()).isNotBlank();
BDDAssertions.then(UserSaved.getFirstName()).isEqualToIgnoringCase("prenom21");
BDDAssertions.then(UserSaved.getLastName()).isEqualToIgnoringCase("Nom21");
BDDAssertions.then(UserSaved.getLastName()).isNotBlank();
}
#Test
#Order(2)
#DisplayName("Test d'existence du user \"prenom21 Nom21\"")
public void readShouldMapCorrectly() throws Exception {
User userStub = new User(idStub, "prenom21", "Nom21");
User userFetched = this.testEntityManager.find(User.class, idStub) ;
String sUserStub = userStub.toString() ;
String sUserFetched = userFetched.toString() ;
boolean bolSameObject = userStub.equals(userFetched) ;
boolean bolAttrEgalEgal = sUserStub == sUserFetched ;
boolean bolStringEqual = sUserStub.equals(sUserFetched) ;
boolean bBeanUtil = helperUtils.haveSamePropertyValues (User.class,userStub,userFetched) ;
Assert.assertTrue(bBeanUtil);
}
}
Maybe it is normal, but what do i have to know ?
I would appreciate some answer please :)
>>>> view complete spring boot app code on github available here
#RunWith(SpringRunner.class) is used for junit 4 test.
But in our case, it is Junit 5 that is used. That is what we can see reading at the pom.xml file (using of junit.jupiter artifact proves that).
So #RunWith(SpringRunner.class) has no effects to manage spring container.
it should be replaced by #ExtendWith(SpringExtension.class).
HOWEVER :
#DataJpaTest already "contains" #ExtendWith(SpringExtension.class) !!!
So we don't need to add #ExtendWith(SpringExtension.class) when #DataJpaTest is used.
#DataJpaTest will allow to test spring data repository layer but will also guarantee spring dependency injection.
That is to say, and roughly speeking, you can use #Autowired annotation for a class which is annotated #DataJpaTest (a spring data repository layer).
From imports junit.jupiter i can see you are using junit-5, were #RunWith belongs to junit-4, and for reference #ExtendWith is not mandataroy for junit-5 test and if you want to use a specific runner you still require the #ExtendsWith but as #DataJpaTest itself is annotated with #ExtendsWith you don't need to do this explicitly
In JUnit 5, the #RunWith annotation has been replaced by the more powerful #ExtendWith annotation.
To use this class, simply annotate a JUnit 4 based test class with #RunWith(SpringJUnit4ClassRunner.class) or #RunWith(SpringRunner.class).

Element Cannot be Resolved as Variable error in a custom annotation for method interception

New to Spring and AOP programming. Working on a spring AOP tutorial to write aspects that intercept method calls. Would like to enable time logging.
As instructed by the tutorial I created a custom annotation for logging and an aspect to define what should be done when this annotation is called.
The code below is the TrackTime annotation:
package com.in28minutes.springboot.tutorial.basics.example.aop;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TrackTime {}
However Eclipse is displaying the errors –
“Element Cannot be Resolved as Variable/Retention Cannot be resolved to a variable”
I then created an aspect called MethodExecutionCalculationAspect with the ‘TrackTime’ annotation.
#Around("#annotation(com.in28minutes.springboot.tutorial.
basics.example.aop.TrackTime)")
MethodExecutionCalculationAspect
package com.in28minutes.springboot.tutorial.basics.example.aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
#Aspect
#Configuration
public class MethodExecutionCalculationAspect {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Around("#annotation
(com.in28minutes.springboot.tutorial.basics.example.aop.TrackTime)")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
joinPoint.proceed();
long timeTaken = System.currentTimeMillis() - startTime;
logger.info("Time Taken by {} is {}", joinPoint, timeTaken);
}
}
#Around uses an around advice. It intercepts the method call and uses joinPoint.proceed() to execute the method.
#annotation(com.in28minutes.springboot.tutorial.basics.example.aop.TrackTime) is the pointcut to define interception based on an annotation — #annotation
followed by the complete type name of the annotation.
Once I correct the annotation and the advice, I’m hoping to use the annotation on methods for time tracking. as shown below:
#Service
public class Business1 {
#TrackTime
public String calculateSomething(){
Any help would be appreciated.
Information about the project is as follows:
SpringBootTutorialBasicsAplication.java:
The Spring Boot application class generated with Spring Initializer. This class acts as the launching point for the application.
• pom.xml: Contains all the dependencies needed to build this project using Spring Boot Starter AOP.
• Business1.java, Business2.java, Dao1.java, Dao2.java: Business classes are dependent on DAO classes.
• We would write aspects to intercept calls to these business and DAO classes.
• AfterAopAspect.java: Implements a few After advices.
• UserAccessAspect.java: Implements a Before advice to do an access check.
• BusinessAopSpringBootTest.java: The unit test that invokes the business methods.
• Maven 3.0+ is your build tool
• Eclipse.
• JDK 1.8+
Your TrackTime is missing imports for RetentionPolicy and Target.
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

How to Register beans from all sub packages in Spring boot app?

I am creating new spring boot + jpa + thymeleaf application, I am using many modules which are placed in sub packages. I have structure like ge.my.project where is placed my main class with #SpringBootApplication and under this package I have sub packages ge.my.project.dao,ge.my.project.service,ge.my.project.controller and so on where are placed my beans.#SpringBootApplication scans only beans under base(ge.my.project) package but I want to scan beans from all sub packages.
I tried many variants to scan sub packages :
#ComponentScan(basePackages = {"ge.my.project.controller","ge.my.project.service","ge.my.project.configuration"})
and
#ComponentScan({"ge.my.project.controller","ge.my.project.service","ge.my.proj
ect.configuration"})
and
#ComponentScan("ge.my.project.*")
but nothing works , When I am trying to inject beans using #Autowired
I am getting error like this Consider defining a bean of type 'ge.my.project.service.ServiceTypeService' in your configuration.
Here is my main class
package ge.my.project;
import ge.ufc.inhouseProjects.controller.ServiceTypeController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
//#ComponentScan(basePackages = {"ge.my.project.controller","ge.my.project.service","ge.my.project.configuration"})
#ComponentScan({"ge.my.project.*"})
#EntityScan({"ge.my.project.entity"})
#EnableJpaRepositories("ge.my.project.dao")
public class InhouseProjectsApplication {
public static void main(String[] args) {
/*ApplicationContext applicationContext = */SpringApplication.run(InhouseProjectsApplication.class, args);
}
}
Here is my full project https://github.com/JavaGeoGroup/inhouseProjects.git
Which is the clearest way to scan all project beans in spring boot application?
You need to annotate the implementation and not the interface. So in your case the #Service annotation needs to be set on ServiceTypeDaoImpl-class instead of ServiceTypeDao-interface.
You need to annotate your beans (your implementation of interfaces, not spring data repo interfaces) with the #Component annotation or one of its sub-annotations like #Repository, #Service, #Controller, #Configuration.
From the javadoc of #Component:
* Indicates that an annotated class is a "component".
* Such classes are considered as candidates for auto-detection
* when using annotation-based configuration and classpath scanning.
*
* <p>Other class-level annotations may be considered as identifying
* a component as well, typically a special kind of component:
* e.g. the {#link Repository #Repository} annotation or AspectJ's
* {#link org.aspectj.lang.annotation.Aspect #Aspect} annotation.
Specific extensions to your code-example:
Spring beans start with a small case, so your interface "ServiceTypeDao"will be registred as "serviceTypeDao" as long as you dont set a specific name in the "#Service" annotation.

Spring boot cannot find beans

i have a Spring Boot project which has some external packages i need to import as Beans in the main application.
So i have my main application in com.package.app package and some classes (among which some repositories) in com.package.commons package.
In order to take these beans i have my main class annotated as follows:
#SpringBootApplication
#ComponentScan({ "com.package.commons" ,"com.package.app"})
#EnableScheduling
#EnableAsync
public class EmanagerApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(EmanagerApplication.class, args);
}
}
But when i launch the application it may occur (not always but very ofter) that the start up fails with these kind of error:
Description:
Field repository in com.package.commons.service.BrandService required a bean of type 'com.package.commons.persistence.repository.BrandRepository' that could not be found.
Action:
Consider defining a bean of type 'com.package.commons.persistence.repository.BrandRepository' in your configuration.
My BrandRepository is annotated with #Repository and the service class with #Service
The really strange thing is that if i keep launching the app at the end it stars... but there is no reason for it...
If you're using JPA, you'll also need the #EnableJpaRepositories annotation.
Also consider to use #EnableTransactionManagement to enable declarative transaction handling.
E.g. use something like the following in the same package or a parent package where you have your JPA entities and JPA repositories (untested):
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.jta.JtaTransactionManager;
#Configuration
#EntityScan
#EnableJpaRepositories
#EnableTransactionManagement
public class HibernateConfig extends JpaBaseConfiguration {
public HibernateConfig(DataSource dataSource, JpaProperties properties, ObjectProvider<JtaTransactionManager> jtaTransactionManager,
ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
super(dataSource, properties, jtaTransactionManager, transactionManagerCustomizers);
}
#Override
protected AbstractJpaVendorAdapter createJpaVendorAdapter() {
return new HibernateJpaVendorAdapter();
}
#Override
protected Map<String, Object> getVendorProperties() {
return new HashMap<>();
}
}
And don't forget to annotate your #Service classes also with #Transactional.
If you confirm that the Application which with the startup method of this application is good, and confirm the #ComponentScan is good also. And the configuration file yaml or properties of JPA also good.
How about trying extends JPA Repository like this:
public class xxxResponsitory extends JpaRepository<T, E>{
...
}
Cause JpaRepository has already annotated with #Repository annotation, T means the type of Primary Key, I always use Integer or Long, autoboxing type. E means the main type of this repository.
Make an example:
Now we have an Entity type named User, the Primary key type of User is Long, I would write the repository like this:
public class UserRepository extends JpaRepository<Long, User>{
...
}
Don't need annotated anything, then, In the service class, #Autowried UserRepository, everything is good to run. But make sure the things that I talk at the start of my answer.
Hope this can help you.

Resources