web-dev-qa-db-ja.com

別のモジュール内のエンティティをスキャンするように休止状態を構成する方法

JPA注釈付きクラスを持つモジュールAとモジュールBがあります。モジュールBには、Aからこれらのエンティティのいくつかを取得する単体テストがあります。両方のモジュールは正常にコンパイルされ、実行時の依存関係はOKに設定されますが、単体テストを実行しようとすると次のエラーが表示されます。

Java.lang.IllegalArgumentException: Unknown entity: MyClassHere
Caused by: org.hibernate.MappingException: Unknown entity: MyClassHere

これは、EntityManager.merge呼び出しで発生します。

モジュールBにはすべてのhibernate構成ファイルなどがあるため、Aからのクラスがエンティティであることを単純に認識していないと推測しています。

Persistence.xmlに以下を追加してみました

<exclude-unlisted-classes>false</exclude-unlisted-classes>

Hibernate.cfg.xmlに追加しました:

<property name="packagesToScan">myNamespace.*</property>

次に:

 <property name="packagesToScan">
                <array>
                    <value>myNamespace.*</value>
                </array>
</property>

「プロパティ」の内容がnullと一致する必要があるというエラーが表示されました。それから私は試しました:

<mapping class="myNamespace.*" />

私は何が欠けていますか?

編集:重要なことを忘れていたのは、2つのモジュールが別々のプロジェクトとしてセットアップされている(Eclipseを使用している)ため、ディレクトリ構造が異なることです。実行時の依存関係はすべて正しく設定されていますが、.classファイルは異なるディレクトリに配置されるため、hibernateはそれらをスキャンしていないと思います。

19
ventsyv
  • Hibernate/springを使用している場合、LocalSessionFactoryBeanオブジェクトを拡張し、プロジェクトをスキャンして、プロジェクト内のエンティティクラスを識別できます。
  • 2つの異なるプロジェクトを言っているので、2つのプロジェクトを解析して問題を解決する1つのエンティティxmlファイルを作成するためのビルド時ユーティリティを作成してみてください。
2
BValluri

エンティティを自動検出するようにプロジェクトを設定すると、META-INF/persistence.xmlが存在するパスのみがスキャンされます(デフォルト)。

に加えて :

<exclude-unlisted-classes>false</exclude-unlisted-classes>

追加の休止状態オプションを設定します。

<property name="hibernate.archive.autodetection" value="class, hbm" />

Hibernate Entity Managerによって自動検出される要素を決定します。

余分なエンティティ(他のjar内)の場合、メインのpersistence.xmlファイルでjar-fileセクションを設定できます。

<persistence>
    <persistence-unit name="myUnit">
        ...
        <class>foo.bar.Entity1</class>
        <class>foo.bar.Entity2</class>
        <jar-file>moduleB.jar</jar-file>
        ...
    </persistence-unit>
</persistence>

Jar-file要素は、管理された永続性クラスを含むパッケージ化された永続性ユニットに表示されるJARファイルを指定しますが、class要素は管理された永続性クラスを明示的に指定します。

META-INFディレクトリにpersistence.xmlが含まれるJARファイルまたはディレクトリは、永続性ユニットのルートと呼ばれます。永続性ユニットのスコープは、永続性ユニットのルートによって決定されます。各永続性ユニットは、永続性ユニットのスコープに固有の名前で識別する必要があります。

よろしく、アンドレ

2

最近、同様の問題を解決し、jarパスをファイルpersistence.xmlに追加しました

<jar-file>file:///C:/yourpath/yourJar.jar</jar-file>

それが役に立てば幸い。

0
Rafael Marins

persistence.xmlには<jar-file>....jar</jar-file>要素:クラスを検索する1つ以上のJARファイルを指定します。

0
sibnick

それを行う簡単な方法

configuration.addAnnotatedClass(Contact.class)

パッケージによるスキャンを使用する場合は、最初にClassLoaderを使用してすべてのクラスをロードします。 Hibernate-orm LocalSessionFactoryBuilder.classのソースコードの例を参照してください

@Bean
public SessionFactory sessionFactory(){

    HibernateConfig configuration = new HibernateConfig();

    Properties properties = hibernateProperties();

    configuration.setProperties(properties);

    configuration.scanPackages("com.atcc.stom.model.entity");

    return configuration.buildSessionFactory();
}

HibernateConfig.class

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.cfg.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;

import javax.persistence.AttributeConverter;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import Java.io.IOException;
import Java.lang.annotation.Annotation;
import Java.util.Set;
import Java.util.TreeSet;

public class HibernateConfig extends Configuration {

    private static final TypeFilter[] DEFAULT_ENTITY_TYPE_FILTERS = new TypeFilter[] {
            new AnnotationTypeFilter(Entity.class, false),
            new AnnotationTypeFilter(Embeddable.class, false),
            new AnnotationTypeFilter(MappedSuperclass.class, false)};

    private static final String RESOURCE_PATTERN = "/**/*.class";

    private static final String PACKAGE_INFO_SUFFIX = ".package-info";

    private final ResourcePatternResolver resourcePatternResolver;

    private static TypeFilter converterTypeFilter;

    static {
        try {
            @SuppressWarnings("unchecked")
            Class<? extends Annotation> converterAnnotation = (Class<? extends Annotation>)
                    ClassUtils.forName("javax.persistence.Converter", Configuration.class.getClassLoader());
            converterTypeFilter = new AnnotationTypeFilter(converterAnnotation, false);
        }
        catch (ClassNotFoundException ex) {
            // JPA 2.1 API not available - Hibernate <4.3
        }
    }

    public HibernateConfig() {
        this(new PathMatchingResourcePatternResolver());
    }

    public HibernateConfig(ClassLoader classLoader) {
        this(new PathMatchingResourcePatternResolver(classLoader));
    }

    public HibernateConfig(ResourceLoader resourceLoader) {
        this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
    }

    public void scanPackages(String... packagesToScan) throws HibernateException {
        Set<String> entityClassNames = new TreeSet<String>();
        Set<String> converterClassNames = new TreeSet<String>();
        Set<String> packageNames = new TreeSet<String>();
        try {
            for (String pkg : packagesToScan) {
                String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
                        ClassUtils.convertClassNameToResourcePath(pkg) + RESOURCE_PATTERN;

                Resource[] resources = this.resourcePatternResolver.getResources(pattern);
                MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
                for (Resource resource : resources) {
                    if (resource.isReadable()) {
                        MetadataReader reader = readerFactory.getMetadataReader(resource);
                        String className = reader.getClassMetadata().getClassName();
                        if (matchesEntityTypeFilter(reader, readerFactory)) {
                            entityClassNames.add(className);
                        }
                        else if (converterTypeFilter != null && converterTypeFilter.match(reader, readerFactory)) {
                            converterClassNames.add(className);
                        }
                        else if (className.endsWith(PACKAGE_INFO_SUFFIX)) {
                            packageNames.add(className.substring(0, className.length() - PACKAGE_INFO_SUFFIX.length()));
                        }
                    }
                }
            }
        }
        catch (IOException ex) {
            throw new MappingException("Failed to scan classpath for unlisted classes", ex);
        }
        try {
            ClassLoader cl = this.resourcePatternResolver.getClassLoader();
            for (String className : entityClassNames) {
                addAnnotatedClass(cl.loadClass(className));
            }
            for (String className : converterClassNames) {
                ConverterRegistrationDelegate.registerConverter(this, cl.loadClass(className));
            }
            for (String packageName : packageNames) {
                addPackage(packageName);
            }
        }
        catch (ClassNotFoundException ex) {
            throw new MappingException("Failed to load annotated classes from classpath", ex);
        }
    }

    private boolean matchesEntityTypeFilter(MetadataReader reader, MetadataReaderFactory readerFactory) throws IOException {
        for (TypeFilter filter : DEFAULT_ENTITY_TYPE_FILTERS) {
            if (filter.match(reader, readerFactory)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Inner class to avoid hard dependency on JPA 2.1 / Hibernate 4.3.
     */
    private static class ConverterRegistrationDelegate {

        @SuppressWarnings("unchecked")
        public static void registerConverter(Configuration config, Class<?> converterClass) {
            config.addAttributeConverter((Class<? extends AttributeConverter<?, ?>>) converterClass);
        }
    }

}
0
Vahe Gharibyan

Spring を使用してエンティティを検出することで、私が取り組んでいるプロジェクトで同様の問題を解決しました。例えば。注釈付きのSpring構成を使用します。

@Configuration
@ComponentScan("com.org.prj.myNamespace1", "com.org.prj.myNamespace2")
public class MyDatabaseConfig {
    @Bean
    public EntityManagerFactory entityManagerFactory() {
        final LocalContainerEntityManagerFactoryBean factory =
            new LocalContainerEntityManagerFactoryBean();

        // ...JPA properties, vendor adaptor, dialect, data source, persistence unit etc...

        factory.setPackagesToScan("com.org.prj.myNamespace1", "com.org.prj.myNamespace2");

        factory.afterPropertiesSet();
        return factory.getObject();
    }

    // ...Data source beans etc...
}
0
Steve Chambers