3 週間以来、私は自分が書いたいくつかのプラグインJarClassLoader
と反射を使用してロードしようとしています。
プラグインの読み込みは完璧ですが、永続性とエンティティ クラスを使用する必要がある場合、次のエラーが発生します。
GRAVE: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.amepa.plugin03.Test.main(Test.java:29)
Caused by: javax.persistence.PersistenceException: No Persistence provider for EntityManager named pu
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:85)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:54)
at plugin.Main.getLocalFactory(Main.java:126)
... 5 more
コマンドラインでプラグインを実行するjava -jar plugin.jar
と、データベースからフェッチされたデータが完全に表示されます。また、永続化 API を使用せず、ドライバー経由で直接接続すると、反射によっても正しい結果が得られます。
エラーがどこから来たのか、可能であればそれを解決する方法を理解したいと思います。
これはプラグインのコードです:
public class Main /*implements PluginImplement*/{
public List<String> getStudent(){
List<Eleves> findElevesEntities = (new ElevesJpaController(getLocalFactory())).findElevesEntities();
List<String> lst = new ArrayList<>();
for(Eleves el : findElevesEntities){
lst.add(el.toString());
System.out.println(" Eleves : "+el.toString());
}
return lst;
}
public static void main(String args[]){
Main m = new Main();
m.getStudent();
}
public static EntityManagerFactory getLocalFactory() {
return Persistence.createEntityManagerFactory("pu");
}
}
これは私の永続化ファイルです:
<?xml version="1.0" encoding="UTF-8"?>
<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">
<persistence-unit name="pu" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>entities.Eleves</class>
<properties>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/emt?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.user" value="user"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
</persistence>
実体
@Entity
@Table(name = "eleves")
@XmlRootElement
public class Eleves implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Column(name = "created")
@Temporal(TemporalType.TIMESTAMP)
private Date created;
@Column(name = "date_bapteme")
@Temporal(TemporalType.DATE)
private Date dateBapteme;
@Column(name = "date_inscription_ecole")
@Temporal(TemporalType.DATE)
private Date dateInscriptionEcole;
@Column(name = "date_naissance")
@Temporal(TemporalType.DATE)
private Date dateNaissance;
@Column(name = "email")
private String email;
@Basic(optional = false)
@Column(name = "nom")
private String nom;
@Basic(optional = false)
@Column(name = "prenom")
private String prenom;
@Column(name = "numero")
private String numero;
public Eleves() {
}
public Eleves(Integer id) {
this.id = id;
}
public Eleves(Integer id, String nom, String prenom) {
this.id = id;
this.nom = nom;
this.prenom = prenom;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getDateBapteme() {
return dateBapteme;
}
public void setDateBapteme(Date dateBapteme) {
this.dateBapteme = dateBapteme;
}
public Date getDateInscriptionEcole() {
return dateInscriptionEcole;
}
public void setDateInscriptionEcole(Date dateInscriptionEcole) {
this.dateInscriptionEcole = dateInscriptionEcole;
}
public Date getDateNaissance() {
return dateNaissance;
}
public void setDateNaissance(Date dateNaissance) {
this.dateNaissance = dateNaissance;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getNom() {
return nom;
}
public void setNom(String nom) {
this.nom = nom;
}
public String getPrenom() {
return prenom;
}
public void setPrenom(String prenom) {
this.prenom = prenom;
}
public String getNumero() {
return numero;
}
public void setNumero(String numero) {
this.numero = numero;
}
@Override
public String toString() {
return "Eleves{" + "id=" + id + ", created=" + created + ", dateBapteme=" + dateBapteme + ", dateInscriptionEcole=" + dateInscriptionEcole + ", dateNaissance=" + dateNaissance + ", email=" + email + ", nom=" + nom + ", prenom=" + prenom + ", numero=" + numero + '}';
}
}
そしてコントローラー:
public class ElevesJpaController implements Serializable {
public ElevesJpaController(EntityManagerFactory emf) {
this.emf = emf;
}
private EntityManagerFactory emf = null;
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
public List<Eleves> findElevesEntities() {
return findElevesEntities(true, -1, -1);
}
public List<Eleves> findElevesEntities(int maxResults, int firstResult) {
return findElevesEntities(false, maxResults, firstResult);
}
private List<Eleves> findElevesEntities(boolean all, int maxResults, int firstResult) {
EntityManager em = getEntityManager();
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
cq.select(cq.from(Eleves.class));
Query q = em.createQuery(cq);
if (!all) {
q.setMaxResults(maxResults);
q.setFirstResult(firstResult);
}
return q.getResultList();
} finally {
em.close();
}
}
public Eleves findEleves(Integer id) {
EntityManager em = getEntityManager();
try {
return em.find(Eleves.class, id);
} finally {
em.close();
}
}
public int getElevesCount() {
EntityManager em = getEntityManager();
try {
CriteriaQuery cq = em.getCriteriaBuilder().createQuery();
Root<Eleves> rt = cq.from(Eleves.class);
cq.select(em.getCriteriaBuilder().count(rt));
Query q = em.createQuery(cq);
return ((Long) q.getSingleResult()).intValue();
} finally {
em.close();
}
}
}
それらはすべて、maven を使用して jar にパッケージ化されています。
jar をロードするメイン クラスは次のとおりです。
public class Test {
public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException{
JarClassLoader jcl = new JarClassLoader();
Class loadClass = jcl.loadClass("plugin.Main");
System.out.println(" Class : "+loadClass);
for(Method m : loadClass.getDeclaredMethods())
System.out.println(" Method : "+m.getName());
Method declaredMethod = loadClass.getDeclaredMethod("getStudent");
try {
Object newInstance = loadClass.newInstance();
declaredMethod.invoke(newInstance);
} catch (IllegalAccessException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalArgumentException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
JarClassLoader
この投稿から派生したクラスです:
http://kalanir.blogspot.com/2010/01/how-to-write-custom-class-loader-to.html
上記のリンクに修正版のコードを追加します。
public class JarClassLoader extends ClassLoader {
private final String jarFile = "path_to_jar.jar"; //Path to the jar file
private Hashtable classes = new Hashtable(); //used to cache already defined classes
public JarClassLoader() {
super(JarClassLoader.class.getClassLoader()); //calls the parent class loader's constructor
}
public Class loadClass(String className) throws ClassNotFoundException {
return findClass(className);
}
public Class findClass(String className) {
byte classByte[];
Class result = null;
result = (Class) classes.get(className); //checks in cached classes
if (result != null) {
return result;
}
try {
return findSystemClass(className);
} catch (Exception e) {
}
try {
className = className.replaceAll("\\.", "/");
JarFile jar = new JarFile(jarFile);
Enumeration<JarEntry> entries = jar.entries();
JarEntry entry = jar.getJarEntry(className + ".class");
InputStream is = jar.getInputStream(entry);
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
int nextValue = is.read();
while (-1 != nextValue) {
byteStream.write(nextValue);
nextValue = is.read();
}
classByte = byteStream.toByteArray();
className = className.replaceAll("/","\\." );
result = defineClass(className, classByte, 0, classByte.length,null);
classes.put(className, result);
return result;
} catch (Exception e)
{ e.printStackTrace();
return null;
}
}
}
前もって感謝します。