使用流过滤器的实体在带有 TomEE 的 OpenJPA 上产生 StringIndexOutOfBoundsException
Entities that uses stream filters yields StringIndexOutOfBoundsException on OpenJPA with TomEE
我在 NetBeans 8.0.2 上使用 OpenJPA 2.0 和 TomEE 1.7.2,在我在实体 class 中添加一些 Java 8 代码之前它工作正常,但现在我启动 TomEE 时出现 StringIndexOutOfBoundsException。
我有一个classPhone
@Entity
@Table(name = "PHONES")
public class Phone implements Serializable, Cloneable {
@Id
@Column(name = "PHONE_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "PHONE_NUMBER", nullable = false)
private String number;
@ManyToOne
@JoinColumn(name = "PERSON_ID", nullable = false)
private Person owner;
}
我有一个class人。
@Entity
@Table(name = "PEOPLE")
public class Person implements Serializable, Cloneable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "PERSON_ID")
private long id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch = FetchType.EAGER)
private Set<Phone> phones;
}
我有一个方法 setPhones,它使用 for 来正确设置所有者:
public void setPhones(Set<Phone> phones) {
if (phones != null && !phones.isEmpty()) {
for (Phone phone : phones) {
if (phone != null) {
phone.setOwner(this);
}
}
}
this.phones = phones;
}
然后,我改为使用 java 8 streams/filters
public void setPhones(Set<Phone> phones) {
if (phones != null && !phones.isEmpty()) {
phones.stream().filter((phone) -> (phone != null)).forEach((phone) -> {
phone.setOwner(this);
});
}
this.phones = phones;
}
进行此更改后,我在启动时收到此消息:
WARNING: An exception was thrown while attempting to perform class file transformation on "com.mydomain.Person": java.lang.StringIndexOutOfBoundsException: String index out of range: 29789
at java.lang.String.checkBounds(String.java:373)
at java.lang.String.<init>(String.java:413)
at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:112)
at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:174)
at org.apache.openjpa.enhance.PCClassFileTransformer.isEnhanced(PCClassFileTransformer.java:241)
at org.apache.openjpa.enhance.PCClassFileTransformer.needsEnhance(PCClassFileTransformer.java:195)
at org.apache.openjpa.enhance.PCClassFileTransformer.transform0(PCClassFileTransformer.java:140)
at org.apache.openjpa.enhance.PCClassFileTransformer.transform(PCClassFileTransformer.java:127)
at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.transform(PersistenceProviderImpl.java:292)
at org.apache.openejb.persistence.PersistenceUnitInfoImpl$PersistenceClassFileTransformer.transform(PersistenceUnitInfoImpl.java:362)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2957)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1210)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1690)
at org.apache.tomee.catalina.LazyStopWebappClassLoader.loadClass(LazyStopWebappClassLoader.java:171)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)
at org.apache.openejb.cdi.CdiScanner.load(CdiScanner.java:299)
at org.apache.openejb.cdi.CdiScanner.process(CdiScanner.java:248)
at org.apache.openejb.cdi.CdiScanner.init(CdiScanner.java:182)
at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:180)
at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:160)
at org.apache.openejb.cdi.CdiBuilder.build(CdiBuilder.java:41)
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:846)
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:652)
at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1261)
at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1100)
at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5416)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:677)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1912)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
我的"solution"是把以前的方法放回去,效果很好。但我希望能够在我的项目中使用 Java 8。
难道我做错了什么?如果是,是什么?
看起来 TomEE 1.7.2 使用旧版本 (1.14.1) 的 "serp" 库来对实体 bean 进行字节码操作。不幸的是,该版本不支持使用一些新的 Java 8 功能(尤其是 lambda)的 类。您可以尝试更新到最新版本的 serp(尽管可能存在不兼容性),看看是否可以正常工作。
检查 this serp issue and this OpenJPA issue 两者似乎都已修复(这意味着最终 TomEE 应该得到更新以在其 JPA 实体 bean 中获得完整的 Java 8 支持)。他们可能会阐明 whether/how 您可以手动更新 TomEE 1.7.2 中的库以更快地获得支持。
我在 NetBeans 8.0.2 上使用 OpenJPA 2.0 和 TomEE 1.7.2,在我在实体 class 中添加一些 Java 8 代码之前它工作正常,但现在我启动 TomEE 时出现 StringIndexOutOfBoundsException。
我有一个classPhone
@Entity
@Table(name = "PHONES")
public class Phone implements Serializable, Cloneable {
@Id
@Column(name = "PHONE_ID", nullable = false)
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
@Column(name = "PHONE_NUMBER", nullable = false)
private String number;
@ManyToOne
@JoinColumn(name = "PERSON_ID", nullable = false)
private Person owner;
}
我有一个class人。
@Entity
@Table(name = "PEOPLE")
public class Person implements Serializable, Cloneable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "PERSON_ID")
private long id;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "owner", fetch = FetchType.EAGER)
private Set<Phone> phones;
}
我有一个方法 setPhones,它使用 for 来正确设置所有者:
public void setPhones(Set<Phone> phones) {
if (phones != null && !phones.isEmpty()) {
for (Phone phone : phones) {
if (phone != null) {
phone.setOwner(this);
}
}
}
this.phones = phones;
}
然后,我改为使用 java 8 streams/filters
public void setPhones(Set<Phone> phones) {
if (phones != null && !phones.isEmpty()) {
phones.stream().filter((phone) -> (phone != null)).forEach((phone) -> {
phone.setOwner(this);
});
}
this.phones = phones;
}
进行此更改后,我在启动时收到此消息:
WARNING: An exception was thrown while attempting to perform class file transformation on "com.mydomain.Person": java.lang.StringIndexOutOfBoundsException: String index out of range: 29789
at java.lang.String.checkBounds(String.java:373)
at java.lang.String.<init>(String.java:413)
at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:112)
at serp.bytecode.lowlevel.ConstantPoolTable.readString(ConstantPoolTable.java:174)
at org.apache.openjpa.enhance.PCClassFileTransformer.isEnhanced(PCClassFileTransformer.java:241)
at org.apache.openjpa.enhance.PCClassFileTransformer.needsEnhance(PCClassFileTransformer.java:195)
at org.apache.openjpa.enhance.PCClassFileTransformer.transform0(PCClassFileTransformer.java:140)
at org.apache.openjpa.enhance.PCClassFileTransformer.transform(PCClassFileTransformer.java:127)
at org.apache.openjpa.persistence.PersistenceProviderImpl$ClassTransformerImpl.transform(PersistenceProviderImpl.java:292)
at org.apache.openejb.persistence.PersistenceUnitInfoImpl$PersistenceClassFileTransformer.transform(PersistenceUnitInfoImpl.java:362)
at sun.instrument.TransformerManager.transform(TransformerManager.java:188)
at sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:428)
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2957)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1210)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1690)
at org.apache.tomee.catalina.LazyStopWebappClassLoader.loadClass(LazyStopWebappClassLoader.java:171)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)
at org.apache.openejb.cdi.CdiScanner.load(CdiScanner.java:299)
at org.apache.openejb.cdi.CdiScanner.process(CdiScanner.java:248)
at org.apache.openejb.cdi.CdiScanner.init(CdiScanner.java:182)
at org.apache.openejb.cdi.OpenEJBLifecycle.startApplication(OpenEJBLifecycle.java:180)
at org.apache.openejb.cdi.ThreadSingletonServiceImpl.initialize(ThreadSingletonServiceImpl.java:160)
at org.apache.openejb.cdi.CdiBuilder.build(CdiBuilder.java:41)
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:846)
at org.apache.openejb.assembler.classic.Assembler.createApplication(Assembler.java:652)
at org.apache.tomee.catalina.TomcatWebAppBuilder.startInternal(TomcatWebAppBuilder.java:1261)
at org.apache.tomee.catalina.TomcatWebAppBuilder.configureStart(TomcatWebAppBuilder.java:1100)
at org.apache.tomee.catalina.GlobalListenerSupport.lifecycleEvent(GlobalListenerSupport.java:130)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5416)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
at org.apache.catalina.startup.HostConfig.deployDescriptor(HostConfig.java:677)
at org.apache.catalina.startup.HostConfig$DeployDescriptor.run(HostConfig.java:1912)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:744)
我的"solution"是把以前的方法放回去,效果很好。但我希望能够在我的项目中使用 Java 8。 难道我做错了什么?如果是,是什么?
看起来 TomEE 1.7.2 使用旧版本 (1.14.1) 的 "serp" 库来对实体 bean 进行字节码操作。不幸的是,该版本不支持使用一些新的 Java 8 功能(尤其是 lambda)的 类。您可以尝试更新到最新版本的 serp(尽管可能存在不兼容性),看看是否可以正常工作。
检查 this serp issue and this OpenJPA issue 两者似乎都已修复(这意味着最终 TomEE 应该得到更新以在其 JPA 实体 bean 中获得完整的 Java 8 支持)。他们可能会阐明 whether/how 您可以手动更新 TomEE 1.7.2 中的库以更快地获得支持。