Spring Data bean config error: Not an managed type: class

Spring Data bean config error: Not an managed type: class

我正在转换基于 JdbcTemplate 的项目以使用 Spring 数据。我收到其他人描述的 "not an managed type: ..." 错误。这通常表示 Spring 数据未找到实体 class。但是,我想我已经正确设置了,但不确定我为什么会收到这个错误。

我的基础数据配置是

package spittr.config;
import javax.inject.Inject;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.context.annotation.Import;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.context.annotation.ComponentScan;

import javax.persistence.EntityManagerFactory;

@Configuration
@Import(DataSourceConfig.class)
@EnableJpaRepositories("spittr.data")
public class DataConfig {

  @Bean
  public LocalContainerEntityManagerFactoryBean   entityManagerFactory(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
    LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
    emf.setDataSource(dataSource);
    emf.setPersistenceUnitName("spittr");
    emf.setJpaVendorAdapter(jpaVendorAdapter);
    emf.setPackagesToScan("spittr");
    return emf;
 }

 @Bean
 public JpaVendorAdapter jpaVendorAdapter() {
      HibernateJpaVendorAdapter adapter = new   HibernateJpaVendorAdapter();
      adapter.setDatabase(Database.MYSQL);
      adapter.setShowSql(true);
      adapter.setGenerateDdl(false);
      adapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
      return adapter;
 }

 @Configuration
 @EnableTransactionManagement
 public static class TransactionConfig {

    @Inject
    private EntityManagerFactory emf;

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }    
  }

  @Bean
  public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
    return new PersistenceExceptionTranslationPostProcessor();
  }

  @Bean
  public JdbcOperations jdbcTemplate(DataSource dataSource) {
   return new JdbcTemplate(dataSource);
  }

}

Spitter 实体 class 在包 spittr 中:

package spittr;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import org.hibernate.validator.constraints.Email;

import org.hibernate.validator.constraints.ScriptAssert;

@ScriptAssert(
        lang = "javascript",
        script = "_this.confirmPassword != null && _this.confirmPassword.equals(_this.password)",
        message = "spitter.password.mismatch.message")

public class Spitter {

  private Long id;

  @NotNull
  @Size(min=5, max=16, message="{username.size}")
  private String username;

  @NotNull
  @Size(min=5, max=25, message="{password.size}")
  private String password;

  private String confirmPassword;

  @NotNull
  @Size(min=2, max=30, message="{firstName.size}")
  private String firstName;

  @NotNull
  @Size(min=2, max=30, message="{lastName.size}")
  private String lastName;

  @NotNull
  @Email
  private String email;

  public Spitter() {}

  public Spitter(String username, String password, String confirmPassword, String firstName, String lastName, String email) {
    this(null, username, password, confirmPassword, firstName, lastName, email);
  }

  public Spitter(Long id, String username, String password, String confirmPassword, String firstName, String lastName, String email) {
    this.id = id;
    this.username = username;
    this.password = password;
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
  }

  // setters/getters...

}

SpitterDao 在包中 spittr.data:

package spittr.data;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import spittr.Spitter;

public interface SpitterDao extends JpaRepository<Spitter, Long> {  

    public Spitter findByUsername(String username);

    @Modifying
    @Query("UPDATE Spitter s SET s.password = :pwd WHERE s.username = :uname")
    public void saveSpitterPassword(@Param("pwd") String password,
                                    @Param("uname") String username);

}

我还有一个单独的服务层,但我认为这不是导致问题的原因。我的服务层由以下两个文件定义:

package spittr.data;

// Interface for SpitterServiceImpl, The Service layer
// implemented in SpitterServiceImpl.java

import spittr.Spitter;

public interface SpitterService {

    public Spitter save(Spitter spitter);

    public Spitter createSpitter(Spitter spitter);

    public Spitter findByUsername(String username);

}

package spittr.data;

import spittr.Spitter;

import javax.inject.Inject;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;


@Service
@Transactional(readOnly = true)
public class SpitterServiceImpl implements SpitterService {

    @Inject SpitterDao spitterDao;

    @Override
    @Transactional(readOnly = false)
    public Spitter save(Spitter spitter) {
        return spitterDao.save(spitter);
    }

    @Override
    @Transactional(readOnly = false)
    public Spitter createSpitter(Spitter spitter) { 
        Spitter savedSpitter = spitterDao.save(spitter);
        spitterDao.saveSpitterPassword(savedSpitter.getPassword(), savedSpitter.getUsername());
        return savedSpitter;
    }

    @Override
    public Spitter findByUsername(String username) {
        return spitterDao.findByUsername(username);
    }

}

我得到的实际异常是

SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spitterServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: spittr.data.SpitterDao spittr.data.SpitterServiceImpl.spitterDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spitterDao': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Not an managed type: class spittr.Spitter
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:293)
....
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: spittr.data.SpitterDao spittr.data.SpitterServiceImpl.spitterDao; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spitterDao': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Not an managed type: class spittr.Spitter
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:509)
...
Caused by: java.lang.IllegalArgumentException: Not an managed type: class spittr.Spitter
    at org.hibernate.ejb.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:169)
...

您忘记用@Entity 注释 Spitter class。每个 Type/Class 你想坚持 JPA/Hibernate 必须用这个注释来注释。

所以异常说:

  • 无法创建 spitterServiceImpl,因为:
  • 无法创建 SpitterDao,因为:
  • Hibernate 说类型不是托管类型 -> @Entity 丢失

PS。你必须用 @Id 注释 id 字段,也许用某种 ov @GeneratedValue


@Entity
public class Spitter {

  @Id
  private Long id;

  ...
}