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个回答

193

尝试添加所有以下内容,在我的应用程序中,它在Tomcat上正常工作。

 @EnableJpaRepositories("my.package.base.*")
 @ComponentScan(basePackages = { "my.package.base.*" })
 @EntityScan("my.package.base.*")   

我正在使用 Spring Boot,当我使用内嵌 Tomcat 时,即使没有 @EntityScan("my.package.base.*") ,一切都正常。但是,当我尝试将应用程序部署到外部 Tomcat 时,我的实体出现了 not a managed type 错误。

额外阅读:

@ComponentScan 用于扫描所有标记为 @Controller、@Service、@Repository、@Component 等的组件。

@EntityScan 用于扫描应用程序中任何配置的 JPA 的所有标记为 @Entity 的实体。


3
同样!为了让我正在进行的 POC 工作,我只需将所有这些内容添加到我的 Spring Boot 应用程序注解中,并使用 com.* 作为匹配器,这似乎很容易地解决了我拥有的来自两个不同的 com.* 命名空间的所有类的问题!@EnableJpaRepositories("com.*") @ComponentScan(basePackages = { "com.*" }) @EntityScan("com.*") - Brad Parks
对我来说完美地工作了。看起来需要使用@EntityScan。 - animo3991
似乎不需要使用 .*,因为它会递归地扫描基础包内的所有内容。 - Gurkirat Singh Guliani
不应该带着星号*,否则它将无法正常工作。 - ACV
带星号*的代码无法正常工作。 - Bibin Zacharias
感谢您区分ComponentScan和EntityScan注释。非常有帮助。 - VinjaNinja

165

使用Spring Boot入口类中的@EntityScan配置实体的位置。

2016年9月更新:对于Spring Boot 1.4+:
请使用org.springframework.boot.autoconfigure.domain.EntityScan而不是org.springframework.boot.orm.jpa.EntityScan,因为...boot.orm.jpa.EntityScan已被弃用自Spring Boot 1.4起。


7
这个选项也不能帮助我。我猜想在我的配置中还缺少其他东西。 - user1578872
7
对我来说也没什么帮助。 - Kostadin Georgiev
1
它对我起作用了,但它是一个已弃用的注释。 - Juan Carlos Puerto
1
谢谢Juan,我已经更新了答案,使用了当前版本的Entity Scan。 - Manish Maheshwari

69

我认为将 @ComponentScan 替换为 @ComponentScan("com.nervy.dialer.domain") 将有效。

编辑:

我添加了一个示例应用程序,演示如何使用BoneCP设置池化数据源连接。

该应用程序与您的结构相同。 我希望这将帮助您解决配置问题。


如果我添加@ComponentScan("com.nervy.dialer.domain"),由于它在不同的包中,我会得到数据源未找到异常。我还添加了该包,如@ComponentScan({"com.nervy.dialer.domain","com.nervy.dialer.common"})。现在仍然出现相同的错误。 - user1578872
1
我添加了一个示例应用程序,演示如何使用BoneCP设置池化数据源连接。https://github.com/azizunsal/SpringBootBoneCPPooledDataSource 该应用程序与您的结构相同。我希望这能帮助您解决配置问题。 - azizunsal
你做了魔法。它运行得很好。感谢你的帮助。我在数据源中有以下注释:@EnableJpaRepositories(entityManagerFactoryRef = "dialerEntityManagerFactory", transactionManagerRef = "dialerTransactionManager", basePackages = { "com.nervytech.dialer.repository"}). 在删除这个注释并只在DialerApplication中添加@EnableJpsRespository后,它开始正常工作了。 - user1578872
我有同样的问题。Spring Boot无法识别我的实体(来自hibernate 4+版本的@DynamicUpdate)。 我已经尝试过在ComponentScan或EntityScan中添加我的模型包,但仍然遇到相同的错误。我的Application类注解如下: SpringBootApplication ComponentScan(basePackages = {"com.example.controllers",   "com.example.services", "com.example.models"}) EnableAutoConfiguration @Configuration @EnableJpaRepositories(basePackages = {"com.example.dao", "com.example.models"}) - Kostadin Georgiev
我们在相同的场景中使用了Hibernated作为JPA提供程序。尝试了所有这些解决方案后,问题仍然存在。将此配置添加到我的应用程序配置文件中,解决了我的问题。hibernate.annotation.packages.to.scan = ${myEntityPackage} - Robin

65

jpa实体不是托管类型

出现在近期Sp版本的根本原因:

在最新版本的Springboot和JDK中,此错误是由于Java EE中使用的“javax”命名空间被替换为Jakarta EE中的“Jakarta”命名空间所导致。

修复方法:

因此,在更新的Spring版本和JDK版本中。例如Spring 6+和JDK 17+,您现在需要将javax.persistence.Entity替换为jakarta.persistence.Entity来解决错误。

更多上下文:

@SakshamGupta。根本原因是:

在2017年,Oracle(收购了Java EE)决定将Java EE的所有权,维护和未来开发转移到Eclipse Foundation。这个转变导致了Jakarta EE的创建。

作为这个过渡的一部分,包命名约定也发生了改变。Java EE中使用的“Javax”命名空间被替换为Jakarta EE中的“Jakarta”命名空间。

因此,Java和Spring Boot的新版本已经从JDK17和Spring Boot v3开始采用Jakarta EE。因此,您需要切换到jakarta.persistence.Entity。这种变化反映了从Java EE到Jakarta EE的转变以及更新的包命名约定。
以下是附加材料:

4
这对我有用,因为我基于之前版本的SpringBoot 3.x.x代码编写我的代码,我对这个答案非常感激,谢谢! - David Brun
3
对于任何遇到此问题的人。如果您正在遵循SpringBoot教程并最终出现此错误,则javax持久性库已更改为jakarta持久性库,这将解决该问题。我非常新手Java,所以这让我措手不及。 - Pipe Runner
jar依赖使用了javax.persistence。不想逐个更新所有注释。使用旧版本(2.5.5)的Spring Boot而不是3.x对我们来说解决了这个问题。 - jgreen
这解决了我的问题。虽然我想知道你是怎么发现用 jakarta 代替 javax 可以解决这个问题的。有什么参考资料吗? - Saksham Gupta

58

如果您配置自己的 EntityManagerFactory Bean,或者从其他项目中复制了这样的持久性配置,那么您必须设置或调整 EntityManagerFactory 配置中的包:

@Bean
public EntityManagerFactory entityManagerFactory() throws PropertyVetoException {
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    vendorAdapter.setGenerateDdl(true);
    LocalContainerEntityManagerFactoryBean factory;
    factory = new LocalContainerEntityManagerFactoryBean();
    factory.setPackagesToScan("!!!!!!package.path.to.entities!!!!!");
    //...
}

要小心“多个”需求,你需要将一个字符串数组作为参数传递给setPackagesToScan(而不是逗号分隔的单个字符串值)。下面说明了这个问题。

    String[] packagesArray = "com.mypackage1,com.mypackage2".split(",");
    em.setPackagesToScan(packagesArray);

请注意,如果您需要传递多个值给setPackagesToScan,则应传递一个字符串[]数组,而不是逗号分隔的包名列表。 - granadaCoder
确实,“factory.setPackagesToScan”是关键解决方案,您必须在此处添加缺失的模型包名称。 - SebastianX
感谢您使用多需求部分 -> XML配置接受逗号分隔的字符串,但由于某些原因,基于Java的配置不支持。 - lukaszrys
清晰的答案和完美的解决方案解决了我的问题。已点赞!谢谢。 - VinjaNinja
我花费了数小时才到达这里。谢谢你。@lukaszrys,你愿意嫁给我吗? - Jin Kwon

54

在我的情况下,问题是因为我忘记为我的实体类添加@javax.persistence.Entity注解。唉!

//The class reported as "not a managed type"
@javax.persistence.Entity
public class MyEntityClass extends my.base.EntityClass {
    ....
}

在我的情况下,我还需要在@Entity注释中设置表名。我在这里设置了一个示例项目:https://github.com/mate0021/two_datasources.git - mate00
这也是我的问题,涉及到Hibernate 6和Spring Boot 3.0.2。 - A. Smith

32

我之所以得到这个错误,是因为我愚蠢地写成了:

public interface FooBarRepository extends CrudRepository<FooBarRepository, Long> { ...

简要解释:通常创建FooBarRepository类来管理FooBar对象(通常代表名为foo_bar的数据表中的数据)。当扩展CrudRepository以创建专门的存储库类时,需要指定正在管理的类型--在这种情况下是FooBar。但我错误地输入了FooBarRepository而不是FooBar。FooBarRepository不是我试图使用FooBarRepository管理的类型(即类)。因此,编译器会发出此错误。

我在例子中用粗体突出了错误的输入部分。删除示例中突出显示的单词"Repository",代码将能够编译。


11
我失去的15分钟,再也无法挽回。 - Oscar Moncayo
@TayabHussain,我更新了帖子并加入了一些解释。希望对你有所帮助。 - Marvo
2
你真是个天才! :) 省了我不少时间。 - Nejatians
1
这对我有帮助,谢谢。 - Mr. Disability
1
我有8年以上的经验,但今天我还是犯了这个错误,有时候我们会忽视甚至最简单的错误。 :D - undefined

25
你可以使用@EntityScan注解并提供你的实体包路径来扫描所有jpa实体。你可以在使用@SpringBootApplication注解的基础应用程序类上使用此注解。
例如:@EntityScan("com.test.springboot.demo.entity")

20

永远不要忘记在领域类上添加@Entity


这个答案对于早已回答(2年前,更多赞同)有什么补充? - hc_dev

13

将此代码放入您的Application.java文件中

@ComponentScan(basePackages={"com.nervy.dialer"})
@EntityScan(basePackages="domain")

这是上面答案的重复。 - Keshu R.

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