Spring Boot - 不是一个受管理的类型。

270

我使用Spring Boot + JPA,在启动服务时遇到了问题。

Caused by: java.lang.IllegalArgumentException: Not an managed type: class com.nervytech.dialer.domain.PhoneSettings
    at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:219)
    at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:68)
    at org.springframework.data.jpa.repository.support.JpaEntityInformationSupport.getMetadata(JpaEntityInformationSupport.java:65)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getEntityInformation(JpaRepositoryFactory.java:145)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:89)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactory.getTargetRepository(JpaRepositoryFactory.java:69)
    at org.springframework.data.repository.core.support.RepositoryFactorySupport.getRepository(RepositoryFactorySupport.java:177)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.initAndReturn(RepositoryFactoryBeanSupport.java:239)
    at org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.afterPropertiesSet(RepositoryFactoryBeanSupport.java:225)
    at org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean.afterPropertiesSet(JpaRepositoryFactoryBean.java:92)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)

以下是 Application.java 文件内容:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
@SpringBootApplication
public class DialerApplication {

    public static void main(String[] args) {
        SpringApplication.run(DialerApplication.class, args);
    }
}

我使用UCp进行连接池,并且以下是数据源的配置:

@Configuration
@ComponentScan
@EnableTransactionManagement
@EnableAutoConfiguration
@EnableJpaRepositories(entityManagerFactoryRef = "dialerEntityManagerFactory", transactionManagerRef = "dialerTransactionManager", basePackages = { "com.nervy.dialer.spring.jpa.repository" })
public class ApplicationDataSource {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = LoggerFactory
            .getLogger(ApplicationDataSource.class);

    /** The Constant TEST_SQL. */
    private static final String TEST_SQL = "select 1 from dual";

    /** The pooled data source. */
    private PoolDataSource pooledDataSource;

用户详细信息服务实现,

@Service("userDetailsService")
@SessionAttributes("user")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

服务层实现,

@Service
public class PhoneSettingsServiceImpl implements PhoneSettingsService {

}

仓库类,

@Repository
public interface PhoneSettingsRepository extends JpaRepository<PhoneSettings, Long> {

}

实体类,

@Entity
@Table(name = "phone_settings", catalog = "dialer")
public class PhoneSettings implements java.io.Serializable {

WebSecurityConfig类,

@Configuration
@EnableWebMvcSecurity
@ComponentScan
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    /**
     * Instantiates a new web security config.
     */
    public WebSecurityConfig() {

        super();
    }

    /**
     * {@inheritDoc}
     * @see org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
            .antMatchers("/login", "/logoffUser", "/sessionExpired", "/error", "/unauth", "/redirect", "*support*").permitAll()
            .anyRequest().authenticated().and().rememberMe().and().httpBasic()
            .and()
            .csrf()
            .disable().logout().deleteCookies("JSESSIONID").logoutSuccessUrl("/logoff").invalidateHttpSession(true);
    }


    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

      auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }

}

以下是包的分类:

  1. Application 类位于 - com.nervy.dialer
  2. Datasource 类位于 - com.nervy.dialer.common
  3. 实体类位于 - com.nervy.dialer.domain
  4. 服务类位于 - com.nervy.dialer.domain.service.impl
  5. 控制器位于 - com.nervy.dialer.spring.controller
  6. 仓库类位于 - com.nervy.dialer.spring.jpa.repository
  7. WebSecurityConfig 位于 - com.nervy.dialer.spring.security

谢谢!


1
我相信你仍然需要告诉Hibernate扫描包以寻找你的实体对象。 - chrylis -cautiouslyoptimistic-
33个回答

8

多模块 Maven 项目

我知道 @EntityScan 的答案已经在以下这些回答中得到了解决:

但是我感觉需要强调这个问题在处理多模块 Maven 项目时可能经常出现

在我的情况下,我有一个多模块 Maven 项目,其中一个模块是model包,而其他的是microservices。在我的情况下,当我运行使用位于model package(在我的项目中称为domain)中定义的类的微服务时,我必须向@SpringBootApplication class添加@EntityScan(basePackages = {"com.example.domain"})注释:

@SpringBootApplication
@EnableEurekaClient
@EntityScan(basePackages = {"com.example.domain"}) // add this so the spring boot context knows where to look for entities
public class DoctorServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(DoctorServiceApplication.class, args);
    }

}

1
非常感谢,你真是我的救命恩人,非常感谢,这正是我遇到的情况。 - Mosa

7
您可能在类定义上错过了@Entity,或者您有明确的组件扫描路径,但该路径不包含您的类。

6

我已将应用程序类移动到父包中,例如:

主类: com.job.application

实体:com.job.application.entity

这样就不需要添加 @EntityScan。


1
这个答案对我有用。谢谢。 - Arpit Tripathi
这个答案对我也有帮助。大家要小心,感谢回答。 - undefined

4

在我的情况下,我犯了一个错误,即使用存储库类作为JpaRepository参数而不是实体类。就像这样:

@Repository
public interface BuyerInspectionRepository extends JpaRepository<BuyerInspectionRepository,Long> {

}

我用实体类BuyerInspection替换了存储库类(repository class)。

@Repository
public interface BuyerInspectionRepository extends JpaRepository<BuyerInspection,Long> {

}

4

我正在使用Spring Boot 2.0,通过用@EntityScan替换@ComponentScan来解决了这个问题。


4

我曾遇到过同样的问题,但只有在运行需要JPA的Spring Boot测试案例时才会出现。最终结果是我们自己的JPA测试配置正在初始化EntityManagerFactory并设置要扫描的包。如果手动设置EntityScan参数,则这显然会覆盖它。

    final LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    factory.setJpaVendorAdapter( vendorAdapter );
    factory.setPackagesToScan( Project.class.getPackage().getName());
    factory.setDataSource( dataSource );

需要注意:如果您仍然遇到困难,应该在org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManagersetPackagesToScan()方法中设置断点,并查看在调用此方法时传递给它的包。


3
我已经复制了类似的问题,出现了“Not a managed type”的错误。
更具体地说:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stockPriceRepository' defined in com.example.stockclient.repository.StockPriceRepository defined in @EnableJpaRepositories declared on StockUiApplication: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not a managed type: class com.example.stockclient.StockPrice

作为一个多模块项目,我需要启用自动配置支持Spring Data JPA,以了解JPA存储库的路径,因为默认情况下,它仅会扫描主应用程序包及其子包以检测JPA存储库。因此,在我的特定用例中,我已经使用了@EnableJpaRepositories来启用包含必要包中的JPA存储库,但没有使用@EntityScan
@EnableJpaRepositories一样,使用@EntityScan也是同样的情况,因为实体类没有放置在主应用程序包中,这是由于多模块项目。
有关更多详细信息,您可以参考此article

3
不要像我一样犯一个显而易见的错误,将模板类型的顺序弄错。确保在模板声明中不要首先放置id,例如:
public interface CapacityBasedProductRepository extends JpaRepository<Long, CapacityBasedProduct> {
}

JPA类是第一项,id列类型是第二项,就像这样:
public interface CapacityBasedProductRepository extends JpaRepository<CapacityBasedProduct, Long> {
}

否则,您将收到有关java.lang.Long是未知实体类型的投诉。 它使用第一个项目来查找要使用的实体。

3
在我的情况下,我错误地从 jakarta.persistence-api 导入类。
javax.persistence.* 导入对我有用:
package foo;
import javax.persistence.Entity;

@Entity
@Table(name = "phone_settings", catalog = "dialer")
public class PhoneSettings implements java.io.Serializable {
   // ...
}

2
另一种解决此问题的方法是...包含@SpringBootApplication的类的包应该是根目录,而所有其他包都应该是子目录。例如:
package com.home

@SpringBootApplication
public class TestApplication{
  springapplication.run....
}
 
package com.home.repo

@Repository
public interface StudentRepo implements JpaRepository<Student, int>{
 ..........
}

package com.home.entity

@Entity
@Table(name = "student")
public class Student{
 ..........
}

这个答案是正确的。作为一个Java新手,我正在逐步将一个普通的Spring项目移植到SpringBoot,并通过将所有类放在同一个目录中开始了一个快速而肮脏的POC,结果出现了上述异常。请确保至少从JpaRepository派生的类和标记为@Entity的类位于它们自己的包中。 - Hernan Veiras
1
在两个Spring Boot应用程序之间共享实体时遇到了同样的问题。包必须按照一种方式组织,即应用程序是父级,实体必须是子级。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接