I am building a Spring-boot application where I am using Spring data jpa feature.
Please find below my dao layer code
package com.adv.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface CustomerDao extends JpaRepository<Customer, String> {
}
I am using a DaoProvider class as follows:
package com.adv.dao;
import java.io.Serializable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class DaoProvider implements Serializable {
private static final long serialVersionUID = 1L;
#Autowired
private CustomerDao customerDao;
public CustomerDao getCustomerDao() {
return customerDao;
}
}
My spring boot main class is defined as follows:
#SpringBootApplication
#ComponentScan(basePackages="com.adv")
public class AdvMain extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(AdvMain.class);
}
public static void main(String[] args) {
SpringApplication.run(AdvMain.class, args);
}
}
Now during runtime I am getting following exception:
Field customerDao in com.adv.dao.DaoProvider required a bean of type 'com.adv.dao.CustomerDao' that could not be found.
I guess that #Repository annotation on interface CustomerDao is not working.
But I am unable to figure out the issue.Can anyone figure out the problem?
Try to add #EnableJpaRepositories("com.adv.dao") on AdvMain as suggested by #hang321 on Can't Autowire #Repository annotated interface in Spring Boot
Ask
Remove the annotation #Repository from the dao interface. That annotation must be put only on implented classes.
Be careful also to implement both the empty constructor than the all args constructor of the Customer class.
Just remove the #ComponentScan annotation altogether.The #SpringBootApplication annotation already includes the component scan as specified here.
Related
I have the following 3 modules in my spring-boot application:
web (Entry point / Main Application class annotated with #SpringBootApplication
persistence
service
I'm now trying to inject a service in the web module which comes from the service. In the service I'm injecting the repository which comes from the persistence module. When I start the application the following error shows up:
***************************
APPLICATION FAILED TO START
***************************
Description:
Parameter 0 of constructor in com.project.service.images.ImageService required a bean of type 'com.project.persistence.repositories.ImageRepository' that could not be found.
Action:
Consider defining a bean of type 'com.project.persistence.repositories.ImageRepository' in your configuration.
ImageService class:
package com.project.service.images;
import com.project.common.entities.Image;
import com.project.persistence.repositories.ImageRepository;
import com.project.service.AbstractService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.persistence.EntityNotFoundException;
import java.util.Date;
import java.util.List;
#Component
public class ImageService extends AbstractService {
private final ImageRepository imageRepository;
#Autowired
public ImageService(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}
public Image getImage(Long id) {
return imageRepository.findById(id).orElseThrow(EntityNotFoundException::new);
}
public List<Image> getAll() {
return imageRepository.findAll();
}
public List<Image> getAll(Date from) {
return imageRepository.findByDateRange(from, null);
}
public List<Image> getAll(Date from, Date to) {
return imageRepository.findByDateRange(from, to);
}
public List<Image> getAllForDay(Date day) {
return imageRepository.findAll();
}
}
ImageRepository class:
package com.project.persistence.repositories;
import com.project.common.entities.Image;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import java.util.Date;
import java.util.List;
#Repository
public interface ImageRepository extends JpaRepository<Image, Long> {
#Query("SELECT i FROM Image i WHERE i.created > :from AND i.created < :to")
public List<Image> findByDateRange(#Param("from") Date from, #Param("to") Date to);
}
And that's how I inject the service into my class in the web module:
#Autowired
private ImageService imageService;
So on I was searching throught the internet and saw some people with similar problems. Then I got the tip that I should add the scanBasePackages to the SpringBootApplication annotation at my application class. So I did this:
package com.project.web;
#SpringBootApplication(scanBasePackages = "com.project.service")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
But it's still not working. If I add the specific package for scanning to the annotation com.project.service.images the injection of the ImageService works but then it can't find the ImageRepository in it.
What am I doing wrong?
I know that so many modules doesn't make sense for such a small application but I have to because it's for my apprenticeship and we need to make multiple modules.
What normally should do is to have this structure in your app
app
SpringBootApp.java
app.repositories
Repository.java
app.services
Service.java
If you are not following that package structure, then you need to have
#EnableJpaRepositories
And watch out for your entities which may have the same issue, in that case take a look at:
#EntityScan
Just try to change scanBasePackages to "com.project". Repository is in a different package.
eg:
#SpringBootApplication(scanBasePackages = "com.project")
Spring is not able to scan your repository class as it resides in different package.
As per your response in comments, your Application class in under
com.project.web
, so by default Spring will scan all classes under this packages and subpackages. So you need to put all your spring components under the same package/sub package where your application resides.
Create a config class , and define all you beans in that one location , in this case you need the bean for ImageRepository, Something like...
#Configuration
#ComponentScan
public class Config {
#Bean
public ImageRepository getImageRepository() {
// return the image repository object
}
}
I'm trying to use Spring's autowire annotation in my test class in order to inject an instance of a class.
package com.mycom.mycust.processing.tasks.references;
public class ReferenceIdentifierTest {
#Autowired
private FormsDB formsDB;
#PostConstruct
#Test
public void testCreateTopLevelReferencesFrom() throws Exception {
ReferenceIdentifier referenceIdentifier = new ReferenceIdentifier(formsDB);
}
}
This is the FormsDB class:
package com.mycom.mycust.mysql;
import org.springframework.stereotype.Component;
import java.sql.SQLException;
#Component
public class FormsDB extends KeyedDBTable<Form> {
public FormsDB(ConnectionFactory factory) throws SQLException {
super(factory.from("former", new FormsObjectMapper()));
}
}
And here is the SpringBootApplication class:
package com.mycom.mycust.processing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan("com.mycom.mycust")
public class Processing implements CommandLineRunner {
// Code
}
When I run my test, formsDB is null. Since I've used the PostConstruct annotation on the test function I think that FormsDB could not be autowired due to the class not being found. There is also an IntelliJ warning on the Autowired annotation in test class: Autowired members must be defined in valid Spring bean (#Component|#Service...). But I have put the Component annotation above the FormsDB class and I've also put the path com.mycom.mycust in the ComponentScan annotation of the SpringBootApplication. So I can't see why it can't find the class.
What is wrong here?
Your test calls is missing some important annotations to make autowiring work:
#SpringBootTest
#RunWith(SpringRunner.class)
public class ReferenceIdentifierTest {
#Autowired
private FormsDB formsDB;
#Test
public void testCreateTopLevelReferencesFrom() throws Exception {
ReferenceIdentifier referenceIdentifier = new ReferenceIdentifier(formsDB);
}
}
also you can remove #PostConstruct that does not make sense in a test.
I'm getting the following error when trying to run my app:
Field edao in com.alon.service.EmployeeServiceImpl required a bean of
type 'com.alon.repository.EmployeeRepository' 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.alon.repository.EmployeeRepository' in your configuration.
Project structure:
EmployeeRepository:
package com.alon.repository;
import com.alon.model.Employee;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface EmployeeRepository {
List<Employee> findByDesignation(String designation);
void saveAll(List<Employee> employees);
Iterable<Employee> findAll();
}
EmployeeServiceImpl:
package com.alon.service;
import com.alon.model.Employee;
import com.alon.repository.EmployeeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeRepository edao;
#Override
public void saveEmployee(List<Employee> employees) {
edao.saveAll(employees);
}
#Override
public Iterable<Employee> findAllEmployees() {
return edao.findAll();
}
#Override
public List<Employee> findByDesignation(String designation) {
return edao.findByDesignation(designation);
}
}
MyApplication:
package com.alon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyApplicataion {
public static void main(String[] args) {
SpringApplication.run(MyApplicataion.class, args);
}
}
As you have added spring-boot tag I guess you are using sprig data jpa. Your repository interfaces should extend org.springframework.data.repository.Repository (a marker interface) or one of its sub interfaces (usually org.springframework.data.repository.CrudRepository) for instructing spring to provide a runtime implementation of your repository, if any of those interfaces are not extened you'll get
bean of type 'com.alon.repository.EmployeeRepository' that could not
be found.
I assume you try to use spring data JPA. What you can check / debug is:
Is JpaRepositoriesAutoConfiguration executed? You can see this in the start up log in the debug log level
Does something change if you addionally add #EnableJpaRepositories with the corresponding basepackages.
Add #ComponentScan with the corresponding packages, normally #SpringBootApplication should do it, but just in case.
you can also check the autconfig documentation: https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
EDIT: see comment from #ali4j: I did not see that it is the generic spring Repository interface and not the spring data interface
regards,WiPu
I have a spring bean class with a constructor with multiple parameters and #Inject annotation.
Is there a way to use spring Java configuration class to create a bean for the class without actually writing code for creating the object? Something like using #Bean on a field?
#Bean(MyClassName.class) private MyInterfaceName myBean;
Or maybe by making the configuration class abstract and the bean method abstract, like:
#Bean(MyClassName.class) abstract MyInterfaceName myBean();
It's quite annoying (and pointless) to write each time the whole method that only creates a new object if you know that you only have 1 implementation of the class and you want to use auto wiring and constructor injection.
You can use #Component annotation. According to Spring documentation:
#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.
Use the #Component annotation.
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. Other
class-level annotations may be considered as identifying a component
as well, typically a special kind of component: e.g. the #Repository
annotation or AspectJ's #Aspect annotation.
Here is an example:
import org.springframework.stereotype.Component;
#Component
public class CustomerDAO
{
#Override
public String toString() {
return "Hello , This is CustomerDAO";
}
}
A DAO class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
#Component
public class CustomerService
{
#Autowired
CustomerDAO customerDAO;
#Override
public String toString() {
return "CustomerService [customerDAO=" + customerDAO + "]";
}
}
And a runner class:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App
{
public static void main( String[] args )
{
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] {"Spring-AutoScan.xml"});
CustomerService cust = (CustomerService)context.getBean("customerService");
System.out.println(cust);
}
}
And your output:
CustomerService [customerDAO=Hello , This is CustomerDAO]
I have a class called RepositoryConfig.java which extends RepositoryRestConfigurerAdapter. The class has a method
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration conf){
conf.exposeIdsFor(SuperClass.class);
}
Previous versions of Spring would expose the ids in JSON for all classes that extended the superclass. Now after upgrading to the latest Spring Boot 1.3.2 the id is not exposed for the classes that extend the Superclass. Is there a new way to expose the id for every class extending superclass? Or would I have a line of code that exposes the id for every class that extends superclass?
You can get all entities through the EntityManager and filter them according to your needs:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Type;
#Configuration
public class RepositoryConfig extends RepositoryRestConfigurerAdapter {
#Autowired
private EntityManager entityManager;
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.exposeIdsFor(
entityManager.getMetamodel().getEntities().stream()
.map(Type::getJavaType)
.filter(SuperClass.class::isAssignableFrom)
.toArray(Class[]::new));
}
}
Take a look at this answer to see other options.