从jar

时间:2016-10-20 02:06:56

标签: java jar spring-boot spring-data-jpa

我有一个新的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中的实体)

你是否看到我缺少的东西使用一个在jar中声明的@Entity的SpringData / JpaEntity?你有没有做过类似的事情?

这是我的代码:

的pom.xml

<?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实体时。

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

提前谢谢!

4 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分: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;
}

答案 2 :(得分: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>

答案 3 :(得分:0)

我的项目在Spring Boot应用程序中也有类似的问题。我在@Entity之类的包中的公共jar中有com.foo.jpa类,然后有一个依赖于公共jar的应用程序jar。应用程序jar在诸如@SpringBootApplication之类的软件包中具有主com.foo.bar.appname类。 @EntityScan@ComponentScan@EnableJpaRepositories均未检测到@Entity类,并且给出了“不是托管类型”错误,无论我为注释提供了什么包名称。 / p>

我终于通过重命名程序包名称来修复它。我将@SpringBootApplication应用程序类放在com.foo.bar处,并将@Entity类放在公用jar中的com.foo.bar.whatever处。只要公共jar中的@Entity类位于@SpringBootApplication类的同一包或子包中,无论它位于哪个jar中,它都将被自动检测到。