tenticon
tenticon

Reputation: 2943

Spring - CrudRepository is not created

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

Upvotes: 5

Views: 10573

Answers (1)

Plog
Plog

Reputation: 9612

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")

Upvotes: 16

Related Questions