命令行 nashorn 脚本 (jjs) 无法创建实体管理器。为啥?
Posted
技术标签:
【中文标题】命令行 nashorn 脚本 (jjs) 无法创建实体管理器。为啥?【英文标题】:CommandLine nashorn script (jjs) unable to create entity manager. Why?命令行 nashorn 脚本 (jjs) 无法创建实体管理器。为什么? 【发布时间】:2016-05-10 18:29:19 【问题描述】:命令行 nashorn 脚本 (jjs) 无法创建实体管理器。
为什么这不起作用?
如何让它工作(如果有的话)?
即,
运行脚本如下所示...
$ jjs -cp ".;myjpaclasses-1.jar;" myNashornScript.js
即“myNashornScript.js”包含...
/* global Java, java */
print("begin test...");
var EntityManagerFactory = Java.type('javax.persistence.EntityManagerFactory');
var EntityManager = Java.type('javax.persistence.EntityManager');
var Persistence = Java.type('javax.persistence.Persistence');
var Employees = Java.type('aaa.bbb.ccc.jpa.Employees');
var employees = new Employees();
var javaImports = new JavaImporter(java.io, java.lang, java.util);
try
with (javaImports)
var emf = Persistence.createEntityManagerFactory("hr_pu"); <== issue here(?)...
var em = emf.createEntityManager();
var query = em.createQuery(
"SELECT e FROM Employees e WHERE e.employeeId > ?1")
.setParameter(1, 100)
.setFirstResult(0);
var rows = query.getResultList();
//...print info on 2nd row object of returned list...
//...print returned list size...
print("rows.get(2).getFirstName()="+ rows.get(2).getFirstName()
+ "...returned row count=" + rows.size());
catch (e)
print(e.message);
print("end test...");
从命令行运行脚本始终会产生以下结果...
begin test...
No Persistence provider for EntityManager named hr_pu
end test...
注意:fwiw,当从 java 应用程序调用时,此脚本似乎工作正常......即,
package aaa.bbb.ccc.jar;
import java.io.FileNotFoundException;
import java.io.FileReader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class RunScript
public static void main (String[] args) throws ScriptException, FileNotFoundException
ScriptEngineManager engineManager = new ScriptEngineManager();
ScriptEngine engine = engineManager.getEngineByName("nashorn");
engine.eval(new FileReader("src/main/resources/myNashornScript.js"));
...即,产生...
begin test...
[EL Warning]: transaction: 2016-05-12 14:18:00.773--ServerSession(1829217853)--PersistenceUnitInfo hr_pu has transactionType RESOURCE_LOCAL and therefore jtaDataSource will be ignored
[EL Info]: 2016-05-12 14:18:00.78--ServerSession(1829217853)--EclipseLink, version: Eclipse Persistence Services - 2.6.3.v20160428-59c81c5
[EL Info]: connection: 2016-05-12 14:18:01.183--ServerSession(1829217853)--/file:/C:/tools/netbeansWS/myjpaclasses/target/classes/_hr_pu login successful
rows.get(2).getFirstName()=Alexander...returned row count=106
end test...
感谢您的帮助/指导!
附言
如果有什么不同,persistence.xml(位于“myjpaclasses.jar”的 src/main/resources/META-INF 中)如下所示:
<?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="hr_pu" transaction-type="RESOURCE_LOCAL">
<jta-data-source>jdbc/HR</jta-data-source>
<class>aaa.bbb.ccc.jpa.Regions</class>
<class>aaa.bbb.ccc.jpa.Employees</class>
<class>aaa.bbb.ccc.jpa.Departments</class>
<class>aaa.bbb.ccc.jpa.Locations</class>
<class>aaa.bbb.ccc.jpa.Jobs</class>
<class>aaa.bbb.ccc.jpa.Countries</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:oracle:thin:@localhost:1521:XE"/>
<property name="javax.persistence.jdbc.user" value="HR"/>
<property name="javax.persistence.jdbc.password" value="HR"/>
</properties>
</persistence-unit>
</persistence>
JPA“雇员”类如下所示:
package aaa.bbb.ccc.jpa;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import javax.xml.bind.annotation.*;
@XmlAccessorType(XmlAccessType.FIELD)
@Entity
@Table(name = "EMPLOYEES", uniqueConstraints = @UniqueConstraint(columnNames = "EMAIL"))
@XmlRootElement
public class Employees implements Serializable
@Column(name = "LAST_NAME", table = "EMPLOYEES", nullable = false, length = 25)
@Basic
private String lastName;
@Column(name = "HIRE_DATE", table = "EMPLOYEES", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
@Basic
private Date hireDate;
@ManyToOne(targetEntity = Departments.class)
@JoinColumn(name = "DEPARTMENT_ID", referencedColumnName = "DEPARTMENT_ID")
private Departments departmentId;
@Column(name = "EMPLOYEE_ID", table = "EMPLOYEES", nullable = false)
@Id
private Integer employeeId;
@ManyToOne(targetEntity = Employees.class)
@JoinColumn(name = "MANAGER_ID", referencedColumnName = "EMPLOYEE_ID")
private Employees managerId;
@Column(name = "SALARY", table = "EMPLOYEES", scale = 2, precision = 8)
@Basic
private BigDecimal salary;
@Column(name = "COMMISSION_PCT", table = "EMPLOYEES", scale = 2, precision = 2)
@Basic
private BigDecimal commissionPct;
@XmlTransient
@OneToMany(targetEntity = Employees.class, mappedBy = "managerId")
private List<Employees> employeesCollection;
@Column(name = "FIRST_NAME", table = "EMPLOYEES", length = 20)
@Basic
private String firstName;
@ManyToOne(optional = false, targetEntity = Jobs.class)
@JoinColumn(name = "JOB_ID", referencedColumnName = "JOB_ID")
private Jobs jobId;
@Column(name = "PHONE_NUMBER", table = "EMPLOYEES", length = 20)
@Basic
private String phoneNumber;
@XmlTransient
@OneToMany(targetEntity = Departments.class, mappedBy = "managerId")
private List<Departments> departmentsCollection;
@Column(name = "EMAIL", table = "EMPLOYEES", nullable = false, length = 25)
@Basic
private String email;
public Employees()
public String getLastName()
return this.lastName;
public void setLastName(String lastName)
this.lastName = lastName;
public Date getHireDate()
return this.hireDate;
public void setHireDate(Date hireDate)
this.hireDate = hireDate;
public Departments getDepartmentId()
return this.departmentId;
public void setDepartmentId(Departments departmentId)
this.departmentId = departmentId;
public Integer getEmployeeId()
return this.employeeId;
public void setEmployeeId(Integer employeeId)
this.employeeId = employeeId;
public Employees getManagerId()
return this.managerId;
public void setManagerId(Employees managerId)
this.managerId = managerId;
public BigDecimal getSalary()
return this.salary;
public void setSalary(BigDecimal salary)
this.salary = salary;
public BigDecimal getCommissionPct()
return this.commissionPct;
public void setCommissionPct(BigDecimal commissionPct)
this.commissionPct = commissionPct;
@XmlTransient
public List<Employees> getEmployeesCollection()
return this.employeesCollection;
public void setEmployeesCollection(List<Employees> employeesCollection)
this.employeesCollection = employeesCollection;
public String getFirstName()
return this.firstName;
public void setFirstName(String firstName)
this.firstName = firstName;
public Jobs getJobId()
return this.jobId;
public void setJobId(Jobs jobId)
this.jobId = jobId;
public String getPhoneNumber()
return this.phoneNumber;
public void setPhoneNumber(String phoneNumber)
this.phoneNumber = phoneNumber;
@XmlTransient
public List<Departments> getDepartmentsCollection()
return this.departmentsCollection;
public void setDepartmentsCollection(List<Departments> departmentsCollection)
this.departmentsCollection = departmentsCollection;
public String getEmail()
return this.email;
public void setEmail(String email)
this.email = email;
用于创建“myjpaclasses-1.jar”的 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>aaa.bbb.ccc.jar</groupId>
<artifactId>myjpaclasses</artifactId>
<version>1</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.test.skip>false</maven.test.skip>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<timestamp>$maven.build.timestamp</timestamp>
<maven.build.timestamp.format>yyyyMMdd.HHmmss</maven.build.timestamp.format>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>eclipselink</artifactId>
<version>2.6.3</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>7.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc7</artifactId>
<version>12.1.0.2</version>
</dependency>
</dependencies>
<build>
<!-- use for snapshot versioning <finalName>$project.artifactId-$project.version-$maven.build.timestamp</finalName> -->
<finalName>$project.artifactId-$project.version</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<excludes>
<exclude>junit:junit</exclude>
</excludes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<name>myjpaclasses</name>
</project>
【问题讨论】:
【参考方案1】:可能EntityManager / JPA 库要求持久性库类加载器是线程上下文类加载器。使用 jjs -cp 选项,创建一个新的类加载器,它不是线程上下文类加载器。使用“java -cp”,应用程序类加载器在初始化期间被设置为线程上下文加载器。
您可能想在 .js 脚本中尝试以下操作:
var EntityManagerFactory = Java.type('javax.persistence.EntityManagerFactory');
// set the thread context class to be the loader of EntityManagerFactory class
var cls = EntityManagerFactory.class;
java.lang.Thread.currentThread().contextClassLoader = cls.classLoader;
//... rest of your script..
如果可行,请告诉我。
【讨论】:
宾果游戏! (即,有效)... - 非常感谢 A. Sundararajan,感谢您的慷慨帮助/专业知识!以上是关于命令行 nashorn 脚本 (jjs) 无法创建实体管理器。为啥?的主要内容,如果未能解决你的问题,请参考以下文章