【技術】JavaSE環境におけるJPAエンティティークラスの自動登録
10130 ワード
コンテナのサポートがない環境では、JPAのエンティティーはpersistenceにあるのが一般的である.xmlには、次のように1つずつ登録されています.
皆さんは私と同じように面倒な感じがするかどうか分からないし、疑問もあります.実体クラスごとに@Entityがマークされているのに、どうしてもう一度登録しなければならないのですか.@Entityタグを利用して、エンティティクラスの登録を免除する方法はありますか?研究を経て、以下の案を見つけて、みんなに分かち合います.
まず、私が使用しているJPA実装がEclipselinkであることを説明し、私の案もこの実装の下で検証しただけです.
EntityManagerFactoryがPersistenceProviderによって作成されたことを知っています.このクラスは異なるJPA実装において異なる実装クラスがあり、Eclipselinkではorg.eclipse.persistence.jpa.PersistenceProvider、私たちはまずこのクラスを継承し、その中を上書きする方法createEntityManagerFactoryImplは、以下の通りです.
原理説明:4行目、persistence.xmlにエンティティクラスが登録されていない場合、classNameリストは空のリストになります(nullではなくemptyリストに注意してください).5行目で、メソッドgetManagedClassNameによってエンティティークラスを取得します.6行目は、エンティティクラスをリストに追加します.7行目では、親メソッドを呼び出し、ファクトリクラスの作成を実現します.次のキーはgetManagedClassNamesメソッドの実装です.ここではgoogleのオープンソースプロジェクトguavaを使用してjavaクラスをスキャンし、@Entityタグのあるエンティティクラスをフィルタします.コードは以下の通りです.
ここでクラスローダ(loader)は具体的には使用するが、特殊なClassLoaderを使用する場合はorgを上書きする必要がある.eclipse.persistence.jpa.PersistenceProviderのgetClassLoaderメソッドは、実行時にエンティティクラスが正常にロードされることを保証します.
また、PersisitenceProviderは、プロファイルpersistenceによるものではなく、SPIによってロードすることが実験で分かった.xmlでの設定.そのため、META-INFでservices/javaxを追加する必要がある.persistence.spi.PersistenceProviderファイル、このファイルに自分のPersistenceProviderを書き込みます.この点についてはまだ疑問がありますが、実践の中で検証してください.
1 <?xml version="1.0" encoding="UTF-8"?>
2 <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
3 <persistence-unit name="security-common">
4 <class>org.gems.han.security.common.MenuVO</class>
5 <class>org.gems.han.security.common.MenuItemVO</class>
6 <class>org.gems.han.security.common.ModuleVO</class>
7 <class>org.gems.han.security.common.RoleVO</class>
8 <class>org.gems.han.security.common.UserVO</class>
9 <class>org.gems.han.security.common.UserRoleVO</class>
10 </persistence-unit>
11 </persistence>
皆さんは私と同じように面倒な感じがするかどうか分からないし、疑問もあります.実体クラスごとに@Entityがマークされているのに、どうしてもう一度登録しなければならないのですか.@Entityタグを利用して、エンティティクラスの登録を免除する方法はありますか?研究を経て、以下の案を見つけて、みんなに分かち合います.
まず、私が使用しているJPA実装がEclipselinkであることを説明し、私の案もこの実装の下で検証しただけです.
EntityManagerFactoryがPersistenceProviderによって作成されたことを知っています.このクラスは異なるJPA実装において異なる実装クラスがあり、Eclipselinkではorg.eclipse.persistence.jpa.PersistenceProvider、私たちはまずこのクラスを継承し、その中を上書きする方法createEntityManagerFactoryImplは、以下の通りです.
1 @Override
2 protected EntityManagerFactoryImpl createEntityManagerFactoryImpl(PersistenceUnitInfo puInfo, Map properties,
3 boolean requiresConnection) {
4 List<String> classNameList = puInfo.getManagedClassNames();
5 List<String> entityClassNameList =getManagedClassNames();
6 classNameList.addAll(entityClassNameList);
7 return super.createEntityManagerFactoryImpl(puInfo, properties, requiresConnection);
8 }
原理説明:4行目、persistence.xmlにエンティティクラスが登録されていない場合、classNameリストは空のリストになります(nullではなくemptyリストに注意してください).5行目で、メソッドgetManagedClassNameによってエンティティークラスを取得します.6行目は、エンティティクラスをリストに追加します.7行目では、親メソッドを呼び出し、ファクトリクラスの作成を実現します.次のキーはgetManagedClassNamesメソッドの実装です.ここではgoogleのオープンソースプロジェクトguavaを使用してjavaクラスをスキャンし、@Entityタグのあるエンティティクラスをフィルタします.コードは以下の通りです.
1 public List<String> getManagedClassNames() {
2 List<String> managedClassNameList = new ArrayList<>();
3 ClassLoader loader = Thread.currentThread().getContextClassLoader();
4 ImmutableSet<ClassInfo> cs = null;
5 try {
6 cs = ClassPath.from(loader).getTopLevelClasses();
7 } catch (IOException e) {
8 e.printStackTrace();
9 }
10 managedClassNameList = new ArrayList<>();
11 if (cs != null && cs.isEmpty() == false) {
12 for (ClassInfo ci : cs) {
13 Class<?> c = null;
14 try {
15 c = loader.loadClass(ci.getName());
16 } catch (Throwable ex) {
17 }
18 if (c != null) {
19 Entity entity = c.getAnnotation(Entity.class);
20 if (entity != null) {
21 managedClassNameList.add(c.getName());
22 }
23 }
24 }
25 }
26 return managedClassNameList;
27 }
ここでクラスローダ(loader)は具体的には使用するが、特殊なClassLoaderを使用する場合はorgを上書きする必要がある.eclipse.persistence.jpa.PersistenceProviderのgetClassLoaderメソッドは、実行時にエンティティクラスが正常にロードされることを保証します.
また、PersisitenceProviderは、プロファイルpersistenceによるものではなく、SPIによってロードすることが実験で分かった.xmlでの設定.そのため、META-INFでservices/javaxを追加する必要がある.persistence.spi.PersistenceProviderファイル、このファイルに自分のPersistenceProviderを書き込みます.この点についてはまだ疑問がありますが、実践の中で検証してください.