命令行 nashorn 脚本 (jjs) 无法创建实体管理器。为什么?
CommandLine nashorn script (jjs) unable to create entity manager. Why?
CommandLine 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...
注意:首先,当从 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...
感谢任何help/guidance!
P.S.
如果有任何区别,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 "Employee" class 看起来像这样:
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;
}
}
pom.xml 用于创建 "myjpaclasses-1.jar"...
<?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>
EntityManager/JPA 库可能 要求持久性库class 加载程序是线程上下文class 加载程序。使用 jjs -cp 选项,会创建一个新的 class 加载器,而不是线程上下文 class 加载器。使用 "java -cp",应用程序 class 加载器在初始化期间被设置为线程上下文加载器。
您可能想在 .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..
如果可行,请告诉我。
CommandLine 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...
注意:首先,当从 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...
感谢任何help/guidance!
P.S.
如果有任何区别,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 "Employee" class 看起来像这样:
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;
}
}
pom.xml 用于创建 "myjpaclasses-1.jar"...
<?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>
EntityManager/JPA 库可能 要求持久性库class 加载程序是线程上下文class 加载程序。使用 jjs -cp 选项,会创建一个新的 class 加载器,而不是线程上下文 class 加载器。使用 "java -cp",应用程序 class 加载器在初始化期间被设置为线程上下文加载器。
您可能想在 .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..
如果可行,请告诉我。