Spring Boot not autowiring #Repository - spring

I'm trying to configure a datasource with Spring Boot but I'm getting org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.myapp.repository.UserRepository com.mycompany.myapp.service.AuthenticationServiceImpl.userRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.myapp.repository.UserRepository] 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)}
These is my project structure:
Main Class:
package com.mycompany.myapp;
#ComponentScan(basePackageClasses = {com.mycompany.myapp.domain.user.User.class,
com.mycompany.myapp.repository.UserRepository.class,
com.mycompany.myapp.service.AuthenticationServiceImpl.class})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Domain Class:
package com.mycompany.myapp.domain.user
#Entity
public class User {
#Id
#GeneratedValue
private long id;
#Column(nullable = false)
private String name;
#Column(nullable = false)
private String lastName;
#Column(nullable = false)
private String password;
#Column(nullable = false)
private String email;
public User() {}
public User(String email, String password){
this.email = email;
this.password = password;
}
}
Repository:
package com.mycompany.myapp.repository;
public interface UserRepository extends CrudRepository<User, Long> {
List<User> findByLastName(String lastName);
}
Controller
package com.mycompany.myapp.service;
#RestController
public class AuthenticationServiceImpl implements AuthenticationService {
#Autowired
private UserRepository userRepository;
#RequestMapping("/add")
public User add(){
User user = new User();
user.setName("Juan");
user.setLastName("Sarpe");
user.setEmail("email#gmail.com");
userRepository.save(user);
return user;
}
}
application.properties
spring.datasource.url:jdbc:mysql://localhost:3306/mydb
spring.datasource.username=user
spring.datasource.password=pass
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
I guess my app is not detecting my #Repository annotation on UserRepository. As far as I know, Spring Boot will automatically set my class as #Repository because it is extending CrudRepository. What am I doing wrong? (Notice that my Application class is on top of packages hierarchy).

In main class of spring boot you have to use this below annotation :
#SpringBootApplication
#ComponentScan(basePackages = "basepackage")
#EntityScan(basePackages ="basepackage")
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "basepackage")
In Repository layer use below annotation :
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
#Transactional
#Repositor
If you have any service layer then use below annotation in the implementation class:
import org.springframework.stereotype.Service;
#Service

Have you tried #EnableJpaRepositories in your configuration ?

The standard way to configure is to create a base marker repository interface and provide that in the component scan.
public interface RepositoryPackage {
}
Keep the interface RepositoryPackage in the same package as UserRepository.
#ComponentScan(basePackageClasses= "RepositoryPackage.class")
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

Related

Why can't #Autowired a JPA repository - Spring boot + JPA

I'm giving this error:
Parameter 0 of constructor in x.microservice.module.business.application.BusinessCreator required a bean of type 'x.microservice.module.business.infrastructure.HibernateJpaRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=false)
Action:
Consider defining a bean of type 'x.microservice.module.business.infrastructure.HibernateJpaRepository' in your configuration.
The controller:
#Slf4j
#RestController
public final class BusinessPostController {
#Autowired
private BusinessCreator creator;
#PostMapping(value = "/business")
public ResponseEntity create(#RequestBody Request request){
BusinessCreatorDto businessCreatorDto = new BusinessCreatorDto(IdentifierEpoch.generate(),request.getName());
return ResponseEntity.ok(
creator.create(businessCreatorDto)
);
}
}
The Application Layer:
#AllArgsConstructor
#Service
public class BusinessCreator {
#Autowired
private HibernateJpaRepository repository;
public BusinessResponse create(BusinessCreatorDto dto){
Business business = new Business(dto.getId(), dto.getName());
repository.save(business);
return BusinessResponse.fromAggregate(business);
}
}
In the Infrastructure layer
#Repository
public abstract class HibernateJpaRepository implements JpaRepository<Business, Long> {
}
The boot Application:
#EnableJpaRepositories
#SpringBootApplication
public class MicroserviceApplication {
public static void main(String[] args) {
SpringApplication.run(MicroserviceApplication.class, args);
}
}
All dependencies are resolved and the others classes I believe that are irrellevant.
Any suggestions? Thank you very much
Probably, the error cause is HibernateJpaRepository - it has to be an interface that extends JpaRepository.
You could write your own Repository in a interface:
#Repository
public interface HibernateJpaRepository extends JpaRepository < Business, Long > {
}
Then your Class:
#AllArgsConstructor
#Service
public class BusinessCreator {
#Autowired
private HibernateJpaRepository repository;
public BusinessResponse create(BusinessCreatorDto dto){
Business business = new Business(dto.getId(), dto.getName());
repository.save(business);
return BusinessResponse.fromAggregate(business);
}
}

How to #Autwired MessageSource in spring into Entity class correctly?

I have the following entity in spring boot application:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Audited
#XmlRootElement
#XmlAccessorType(XmlAccessType.NONE)
#Table(name = "currency", catalog = "currency_db")
public class Currency implements java.io.Serializable {
#Autowired
Messages messages;
As for message, it just a container of spring MessageSource here it is:
#ApplicationScope
#Component
#Slf4j
public class Messages {
#Autowired
private MessageSource messageSource;
private MessageSourceAccessor accessor;
#PostConstruct
private void init() {
accessor = new MessageSourceAccessor(messageSource, Locale.ENGLISH);
log.info("Messages initialized");
}
public String get(String code) {
return accessor.getMessage(code);
}
}
I'm getting the following error when run mvn clean install. Any idea what I'm missing here?
org.hibernate.MappingException: Could not determine type for: com.company.currencyservice.Messages, at table: currency, for columns: [org.hibernate.mapping.Column(messages)]
It's looks like hibernate think it's a column. Thanks.
Entities are not Spring beans and therefor you cannot use dependency injection in entities.
If you want to access a Spring bean from within an entity you can use a helper class like this:
#Service
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static <T> T bean(Class<T> beanType) {
return context.getBean(beanType);
}
public static Object bean(String name) {
return context.getBean(name);
}
#Override
public void setApplicationContext(#SuppressWarnings("NullableProblems") ApplicationContext ac) {
context = ac;
}
}
Then you can use ApplicationContextProvider.getBean(Messages.class) to get access to the Messages.

#Autowired is not working for CrudRepository

I have problems injecting a repository, there is no problem injecting a Service. Im injecting the repo in a service:
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
and the repository is:
public interface AuthorRepository extends CrudRepository<Author, Integer> {
}
And my code structure is the following:
with the main class:
#SpringBootApplication
public class AuthorBookGraphqlApplication {
public static void main(String[] args) {
SpringApplication.run(AuthorBookGraphqlApplication.class, args);
}
}
the error is thrown on start:
Field repository in com.author.book.graphql.demo.service.AuthorService required a bean of type 'com.author.book.graphql.demo.repository.AuthorRepository' that could not be found.
Update code as below
Spring will automatically import the beans into the container and inject to dependencies with these annotations.
#Component, #Controller, #Service and #Repository - Helps to define the beans so the container is aware of them and can inject them for you with #Autowired.
#Autowired - Handles only wiring part here.
#Service
public class AuthorService {
#Autowired
private AuthorRepository repository;
public String getAll(){return "XXXXX";}
}
#Repository
public interface AuthorRepository extends CrudRepository<Author, Integer> {}
Before class AuthorRepository, Let's put more annotation #Repository.

Spring JPA custom repository different packages

I'm developing a spring boot application and i'm running into an issue here. I want to have separate packages for my RepositoryImpl, RepositoryCustom and Repository classes but when i separate the packages im getting this error:
Caused by:
org.springframework.data.mapping.PropertyReferenceException: No
property customMethod found for type Demo!
It only works when i put my RepositoryImpl, RepositoryCustom and Repository classes into the same package. I've tried #EnableJpaRepositories("com.example.demo.persist") but still not working.
Is there a way i can achieve this?
Here's my code:
DemoApplication.java
#SpringBootApplication
#EnableJpaRepositories("com.example.demo.persist")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
DemoController.java
#RestController
public class DemoController {
#Autowired
DemoService demoService;
#RequestMapping("/test")
public String getUnidades() {
demoService.customMethod();
return "test";
}
}
DemoRepositoryCustom.java
public interface DemoRepositoryCustom {
void customMethod();
}
DemoRepositoryImpl.java
public class DemoRepositoryImpl implements DemoRepositoryCustom {
#Override
public void customMethod() {
// do something
}
}
DemoRepositoryCustom.java
public interface DemoRepository extends JpaRepository<Demo, Long>, DemoRepositoryCustom {
}
Demo.java
#Entity
public class Demo {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id", columnDefinition = "bigint")
private int id;
#NotEmpty
#Column(name = "name", columnDefinition = "VARCHAR(60)", length = 60, unique = false, nullable = false)
private String name;
// ...
DemoService.java
#Service
#Transactional
public class DemoService {
#Autowired
DemoRepository demoRepository;
public void customMethod() {
demoRepository.customMethod();
}
}
application.properties
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.datasource.url=jdbc:mysql://localhost:3306/demo?createDatabaseIfNotExist=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
Autodetection of custom implementations work only in packages below the one declaring the Repository.
But you can make your implementation a bean with the name matching the required class name.
That would be demoRepositoryImpl in your case.
See the documentation for details.
Actually your package hierarchy is not in right order.
Make it like this :
com.example.demo.repository
com.example.demo.repository.custom
com.example.demo.repository.custom.impl
And it will work.

Unsatisfied dependency during test

I have a spring boot 2.0.0 M2 application who run well.
I use autowired on constructor
#RequestMapping(value = "/rest")
#RestController
public class AddressRestController extends BaseController{
private final AddressService AddressService;
#Autowired
public AddressRestController(final AddressService AddressService) {
this.AddressService = AddressService;
}
...
}
#Service
public class AddressServiceImpl extends BaseService implements AddressService {
#Autowired
public AddressServiceImpl(final AddressRepository AddressRepository) {
this.AddressRepository = AddressRepository;
}
private final AddressRepository AddressRepository;
...
}
public interface AddressRepository extends JpaRepository<Address, Integer>, AddressRepositoryCustom {
}
#Repository
public class AddressRepositoryImpl extends SimpleJpaRepository implements AddressRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Autowired
public AddressRepositoryImpl(EntityManager em) {
super(Address.class, em);
}
...
}
When i try to run a basic test
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
#Autowired
private AddressService service;
#MockBean
private AddressRepository restTemplate;
#Test
public void getAddress(){
MockitoAnnotations.initMocks(this);
Pageable page = PageRequest.of(0, 20);
Page<Address> pageAdr = mock(Page.class);
given(this.restTemplate.findAll(page)).willReturn(pageAdr);
Page<AddressDto> pageDto = service.getAddress(page);
}
}
I get this error
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'com.sonos.arcor.service.AddressServiceTest': Unsatisfied dependency
expressed through field 'service'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type ''com.sonos.arcor.service.AddressService'
available: expected at least 1 bean which qualifies as autowire
candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I don't understand why i get this error.
You need to annotate the test with SpringBootTest so that spring initialize an application context
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications
#SpringBootTest
#RunWith(SpringJUnit4ClassRunner.class)
public class AddressServiceTest {
// the remaining test
}
Also you do not need MockitoAnnotations.initMocks(this);
Spring takes care of the mock handling
When [#MockBean is]used on a field, the instance of the created mock will also be
injected. Mock beans are automatically reset after each test method
see Mocking and spying beans

Resources