从jar中使用@entity时,Spring Data Jpa存储库无法正常工作

问题描述 投票:5回答:4

我有一个新的SpringBoot应用程序来公开一些与生活在jar中的实体相关的服务(作为POM中的依赖项包含在内)。对于数据访问,我计划使用SpringData,因此我可以使用优秀的JpaRepository而不是手动编写DAO。

从代码中可以看到jar,所以一切都编译得很好,但是当Spring开始连接bean时,它会抛出异常:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.companyName.common.countrytype.Country
    at org.hibernate.jpa.internal.metamodel.MetamodelImpl.managedType(MetamodelImpl.java:210) ~[hibernate-entitymanager-5.0.11.Final.jar:5.0.11.Final]
    at org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation.<init>(JpaMetamodelEntityInformation.java:70) ~[spring-data-jpa-1.10.3.RELEASE.jar:na]

我已经尝试添加指向扩展JpaRepository的接口包的@EnableJpaRepositories但仍然没有成功。

但是,如果我使用粘贴在我的新项目中的@Entity副本,一切都会很好。 (而不是使用jar中的实体)

你是否看到我在Spring Data / Jpa Entity中使用的东西在jar中声明了@Entity?你有没有做过类似的事情?

这是我的代码:

pom.hml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.mycompany</groupId>
	<artifactId>country-service</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>country-service</name>
	<description>Spring Boot country-service</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.4.1.RELEASE</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>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-ws</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>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.mycompany</groupId>
			<artifactId>mycompany-core</artifactId>
			<version>1.1.20</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

入口点:

package com.mycompany.admin.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories(basePackages={"com.mycompany.admin.api"}) //tried this but does not work
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

库:

package com.mycompany.admin.api;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import com.mycompany.common.countrytype.Country;  //This is located in a jar included as dependency in the pom

public interface CountryRepository extends JpaRepository<Country,  Long> {

}

一个简单的控制器来测试:

package com.mycompany.admin.api;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.mycompany.common.countrytype.Country;

@Controller
public class CountryController {

    @Autowired
    private CountryRepository repo;

    @RequestMapping("/")
    @ResponseBody
    public String greeting() {
        return "Hello";
    }


    @RequestMapping("/countries")
    @ResponseBody
    public String listCountry() {
        List<Country> countries;
        try {
            countries = repo.findAll();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return e.getMessage();
        }
        if (countries.isEmpty()) {
            String errorMst = "no countries found";
            System.out.println(errorMst);
            return errorMst;
        } else {
            return "size:" + countries.size();
        }
    } 
}

实体:

package com.mycompany.admin.api;

import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "country", uniqueConstraints = { @UniqueConstraint(columnNames = "code"), @UniqueConstraint(columnNames = "name") })
public class Country {
    protected Long id;
    private String code;
    private String name;

    protected Country() {
    }

    public Country(Long id, String code, String name) {
        this.id = id;
        this.code = code;
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Column(name = "code", unique = true, nullable = false, length = 2)
    public String getCode() {
        return this.code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    @Column(name = "name", unique = true, nullable = false, length = 100)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        if (!super.equals(o)) {
            return false;
        }

        Country country = (Country) o;

        if (!code.equals(country.code)) {
            return false;
        }
        if (!name.equals(country.name)) {
            return false;
        }

        return true;
    }

    @Override
    public int hashCode() {
        int result = super.hashCode();
        result = 31 * result + code.hashCode();
        result = 31 * result + name.hashCode();
        return result;
    }

}

奇怪的是,如果我删除行“import com.mycompany.common.countrytype.Country;”在我的Repository和Controller类中,所以代码使用存储在新引导项目中的克隆版本,这可以正常工作。所以问题只发生在使用jar中的Country实体时。

我真的很感激任何提示或建议你可以给我。

先感谢您!

java jar spring-boot spring-data-jpa
4个回答
7
投票

使用@EntityScan("your.lib.package.with.entities")


1
投票

在使用包扫描添加@Bean时,它适用于我

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
    LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
   factory.setDataSource(dataSource());
    factory.setJpaVendorAdapter(vendorAdapter);
    factory.setPackagesToScan("com.xxx.entity"); // This one
    factory.afterPropertiesSet();
    factory.setLoadTimeWeaver(new InstrumentationLoadTimeWeaver());
    return factory;
}

0
投票

在我的项目中,我们遇到了类似的问题。与mvn spring-boot:start一起运行时,@EntityScan工作正常,可以找到所有实体,包括库中的实体。当我们使用java -jar运行springboot应用程序时,应用程序无法找到通过maven依赖项引用的实体。当springboot应用程序作为jar运行时,类加载似乎不同。

您可以指示spring-boot“解包”包含无法找到的实体的JAR依赖项。您可以将以下部分添加到pom.xml

<project>
  ...

  <build>
      <plugins>
          <plugin>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-maven-plugin</artifactId>
              <configuration>
                  <requiresUnpack>
                      <dependency>
                          <groupId>com.yourcompany.package</groupId>
                          <artifactId>some-jar</artifactId>
                      </dependency>
                  </requiresUnpack>
              </configuration>
          </plugin>
      </plugins>
  </build>

</project>

0
投票

我的项目与Spring Boot应用程序有类似的问题。我在@Entity这样的包装中使用了com.foo.jpa类,然后是一个依赖普通jar的应用程序jar。应用程序jar在@SpringBootApplication这样的包中有主要的com.foo.bar.appname类。 @EntityScan@ComponentScan@EnableJpaRepositories没有检测到@Entity类,并且无论我为注释提供了哪些包名,都给出了“Not a managed type”错误。

我最后通过重命名包名来修复它。我把@SpringBootApplicationapplication类放在com.foo.bar@Entity类在com.foo.bar.whatever的普通罐子里。只要普通jar中的@Entity类在@SpringBootApplication类的同一个包或子包中,就会被自动检测,无论它在哪个罐中。

© www.soinside.com 2019 - 2024. All rights reserved.