The CrudRepository
bean
@Repository
public interface UserDao extends CrudRepository<User, Long>
{
List<User> findByFirstNameAndLastName(String firstName, String lastName);
}
for the User
resource
@Entity
@Table(name="User")
public class User
{
@Id
@GeneratedValue
private long id;
@Column(name="first_name")
private String firstName;
@Column(name="last_name")
private String lastName;
/* --- Getters,setters,default constructor -------*/
}
is not created when I start my Spring boot app
Field dao in base.package.service.UserService required a bean
of type 'base.package.dao.UserDao' that could not be found.
but the packages are definitely scanned
@SpringBootApplication(scanBasePackages= {"base.package"})
I got the strong suspicion that it has to do something with the embedded database h2
that I am using. I am trying to create the User
table in schema.sql
CREATE TABLE IF NOT EXISTS User (
id INTEGER NOT NULL AUTO_INCREMENT,
first_name VARCHAR(128) NOT NULL,
last_name VARCHAR(128) NOT NULL,
PRIMARY KEY (id)
);
but as soon as I uncomment IF NOT EXISTS
it throws an error (table already exists). So this firstly means that spring takes charge of created the schema. But I get the feeling that the table is not recreated because in the data.sql
script
INSERT INTO User (id,first_name,last_name) VALUES (1,'Vincent', 'Vega');
I always have to manually increment the id
on startup otherwise i get a
org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PRIMARY KEY ON PUBLIC.USER(ID)"
Here are the jpa properties from application.properties
# below properties create schema, so schema.sql is redundant
spring.jpa.generate-ddl=true
spring.jpa.hibernate.ddl-auto=create-drop
spring.datasource.initialization-mode=always
spring.jpa.database=H2
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:~/testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=TRUE
spring.datasource.name=testdb
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
The reason why I think that the table is never recreated on startup is because I get this error when the app closes
2018-02-02 09:27:47.907 INFO [restartedMain] [StandardService] Stopping service [Tomcat]
2018-02-02 09:27:47.907 WARN [localhost-startStop-1] [WebappClassLoaderBase] The web application [ROOT] appears to have started a thread named [MVStore background writer nio:C:/Users/user/testdb.mv.db] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Object.wait(Native Method)
This is followed by the exception that UserDao
bean is not created.
***************************
APPLICATION FAILED TO START
***************************
Description:
Field dao in base.package.user.service.UserService required a bean of type 'base.package.user.dao.UserDao' that could not be found.
Action:
Consider defining a bean of type 'base.package.user.dao.UserDao' in your configuration.
POM.XML
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.M7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.M5</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
/* .... */
EDIT
Here is the UserService
@Service
public class UserService
{
@Autowired private UserDao dao;
public List<User> findByFirstNameAndLastName(String firstName, String lastName)
{
return dao.findByFirstNameAndLastName(firstName, lastName);
}
public User save(final User user)
{
return dao.save(user);
}
}
EDIT 2
Now I am getting
Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.project.bot.user.User
at org.hibernate.metamodel.internal.MetamodelImpl.managedType(MetamodelImpl.java:472)
at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:72)
at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getEntityInformation(JpaEntityInformationSupport.java:66)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:169)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:107)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:90)
at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:300)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.lambda$afterPropertiesSet$3(RepositoryFactoryBeanSupport.java:287)
at org.springframework.data.util.Lazy.getNullable(Lazy.java:141)
at org.springframework.data.util.Lazy.get(Lazy.java:63)
at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:290)
at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:102)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706)
... 102 common frames omitted
CrudRepository and JPA repository both are the interface of the spring data repository library. Spring data repository reduces the boilerplate code by providing some predefined finders to access the data layer for various persistence layers. JPA repository extends CrudRepository and PagingAndSorting repository.
You are right. Only CRUD methods ( CrudRepository methods) are by default marked as transactional. If you are using custom query methods you should explicitly mark it with @Transactional annotation.
1. @Repository Annotation. In the spring framework, @Component annotation marks a Java class as a bean so the component-scanning mechanism can find it and create its instance into the application context.
CrudRepository provides generic CRUD operation on a repository for a specific type. CrudRepository is a Spring data interface and to use it we need to create our interface by extending CrudRepository. Spring provides CrudRepository implementation class automatically at runtime.
We generally get this type of error when we create the repository as class instead of interface. CrudRepository is an interface, you most probably extend it using an interface only: Wrong (Some times when we create the repository we create a class by mistake ): You might want to read again the question as I already had an interface and not a class.
CrudRepository is an interface not a class. Replace extends with implements. That's wrong. Interfaces extend other interfaces. They do not implement them. As Markus said!
b. Read : 5. Custom Repository Methods CrudRepository provides methods for generic CRUD operation and if we want to add custom methods in our interface that has extended CrudRepository, we can add in following ways. a. We can start our query method names with find...By, read...By, query...By, count...By, and get...By.
The table not being created should not have any impact on whether the bean is defined or not.
I think the problem you have here is that you are not instatiating your repository beans. Spring Data JPA repository beans are not picked up by component scans since they are only interfaces. The @Repository
annotation actually does nothing here.
Spring Data JPA repo beans are created dynamically provided you have supplied the @EnableJpaRepositories
in your configuration.
You may also need to put an @EntityScan to make sure all your @Entity's are recognised by Spring
@SpringBootApplication(scanBasePackages= {"base.package"})
@EnableJpaRepositories("base.package")
@EntityScan("base.package")
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With