cloning
cloning copied to clipboard
ClassNotFoundException when cloning JavaFX's SimpleListProperty
I'm trying to clone a class I have that uses the SimpleListProperty
class from JavaFX 8. But for some reason it's not playing along. I tried finding the cause my self but I kind of got lost in all the cloning logic.
Can you think of any reason why this would fail?
public class CloneTest {
public static void main(String[] args) {
Cloner cloner = new Cloner();
Data myData = new Data();
myData.slp.add("Hello");
SimpleListProperty<Object> simpleListProp = new SimpleListProperty<>();
simpleListProp.set(myData.slp);
// Exception here
Data clonedData = cloner.deepClone(myData);
myData.slp.set(0, "World");
System.out.println(myData.slp.get(0));
System.out.println(clonedData.slp.get(0));
}
public static class Data {
SimpleListProperty<Object> slp = new SimpleListProperty<>(FXCollections.observableArrayList());
}
}
Hi, do you get an exception or the cloned object is not correct?
On 09/11/15 20:14, Sid wrote:
I'm trying to clone a class I have that uses the |SimpleListProperty| https://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/SimpleListProperty.html class from JavaFX 8. But for some reason it's not playing along. I tried finding the cause my self but I kind of got lost in all the cloning logic.
Can you think of any reason why this would fail?
|public class CloneTest { public static void main(String[] args) { Cloner cloner = new Cloner(); Data myData = new Data(); myData.slp.add("Hello"); SimpleListProperty<Object> simpleListProp = new SimpleListProperty<>(); simpleListProp.set(myData.slp); // Exception here Data clonedData = cloner.deepClone(myData); myData.slp.set(0, "World"); System.out.println(myData.slp.get(0)); System.out.println(clonedData.slp.get(0)); } public static class Data { SimpleListProperty<Object> slp = new SimpleListProperty<>(FXCollections.observableArrayList()); } } |
— Reply to this email directly or view it on GitHub https://github.com/kostaskougios/cloning/issues/45.
I get an exception, the clone is never returned. Here's the exact exception for the code above, forgot to include it:
Exception in thread "main" java.lang.NoClassDefFoundError: javafx/beans/property/ListPropertyBase$$Lambda$1/109961541
at sun.reflect.GeneratedSerializationConstructorAccessor3.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at com.rits.cloning.ObjenesisInstantiationStrategy.newInstance(ObjenesisInstantiationStrategy.java:18)
at com.rits.cloning.Cloner.newInstance(Cloner.java:271)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:436)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:453)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:453)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.deepClone(Cloner.java:301)
at poc.CloneTest.main(CloneTest.java:20)
Caused by: java.lang.ClassNotFoundException: javafx.beans.property.ListPropertyBase$$Lambda$1.109961541
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 14 more
I was having this same issue, and found it was happening with any lambdas I had in my code. Converting the lambdas to regular java fixed the issue for me temporarily (though this won't help if you don't have access to the source code using the lambdas). I was able to reliably reproduce it with the following code:
package asdf;
import com.rits.cloning.Cloner;
import org.junit.Test;
public class dev {
@Test
public void run() {
dev2 test = new dev2();
Cloner cloner = new Cloner();
cloner.deepClone(test);
}
}
class dev2 {
dev3 test;
dev2() {
test = new dev3();
}
}
class dev3 {
Runnable r1;
dev3() {
r1 = () -> System.out.println("Hello world!");
}
}
Here's the stacktrace/error I got back:
java.lang.NoClassDefFoundError: asdf/dev3$$Lambda$1/1509514333
at sun.reflect.GeneratedSerializationConstructorAccessor4.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at com.rits.cloning.ObjenesisInstantiationStrategy.newInstance(ObjenesisInstantiationStrategy.java:18)
at com.rits.cloning.Cloner.newInstance(Cloner.java:271)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:436)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:453)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.cloneObject(Cloner.java:453)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:431)
at com.rits.cloning.Cloner.deepClone(Cloner.java:301)
at asdf.dev.run(dev.java:12)
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:497)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
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:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.ClassNotFoundException: asdf.dev3$$Lambda$1.1509514333
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 41 more
I think it has something to do with assigning the results of the lambdas to r1
and the object creation to test
. If you move the scope of those variables to locally in those blocks, it will pass, ie:
package asdf;
import com.rits.cloning.Cloner;
import org.junit.Test;
public class dev {
@Test
public void run() {
dev2 test = new dev2();
Cloner cloner = new Cloner();
cloner.deepClone(test);
}
}
class dev2 {
//dev3 test;
dev2() {
dev3 test = new dev3();
}
}
class dev3 {
//Runnable r1;
dev3() {
Runnable r1 = () -> System.out.println("Hello world!");
}
}
Do that in either dev2 or dev3 in this example individually fixes the problem, it only happens when both are assigning variables in that scope.
Unfortunately this is about as far as I got with trying to find the exact problem. Let me know if there's anything more I can do to help debug this further. For the time being I'm going to refactor our lambdas to get a fix in.
This problem seems to still be an because when I try to clone my own object I get NoClassDefFoundError and the cause is the same: "java.lang.NoClassDefFoundError: javax/swing/plaf/metal/MetalLookAndFeel$$Lambda$9/363771819" all tough I cannot change swings code. Is there no solution to this? Dose this mean that I cant use Cloning for my project?
It seems this is due to the lambda class names contain a /. i.e. com.rits.tests.cloning.Jdk8Class2$$Lambda$1/836514715 Then the classloader replaces / with a dot and tries to load com.rits.tests.cloning.Jdk8Class2$$Lambda$1.836514715 which is not valid. So far I didn't find a work around as the problem is not part of my code.
Also suffering because of this. Just tried to use objenesis 2.5 instead of 2.1, same problem...
PS: The current cloning release 1.9.3 uses objenesis 2.1 from 2013-10-10 (http://objenesis.org/notes.html).
It's probably in general not a good idea to deep-clone a SimpleListProperty instance, since it can have listeners. Deep-cloning will also clone the listeners, which is probably unexpected,
I think we are also having this same problem. We are migrating our application to Java 8 and WildFly 10. I'm surprised nobody has commented on this since January. Is there a solution I missed? Is the actual problem in Objenesis? I'm using the latest Cloner which uses Objenesis 2.5.1. Could it be fixed in 2.6? I'm going to see if I can try that but if anyone has already, you could save me the time. I'm not really sure what else we can do. We had other strategies in our code but I think they were too slow.
I downloaded the cloning library, changed the objenesis library version to 2.6. I thought it seemed to fix the problem at first but I was wrong.
I just published 1.9.6 with objenesis 2.6. But Mike above says it wouldn't fix the problem.
yes, problem is still there with 1.9.6
Has anyone tried creating an issue against the objenesis library? https://github.com/easymock/objenesis/issues There are no open issues at all. I haven't found a good solution around this yet. Some of the lambdas causing me problems are within hibernate so I can't remove those.
@kostaskougios can you open a ticket against Objenesis if that is where the problem is? I could do it but you could probably explain the problem in a ticket a lot better.
I don't think it is an objenesis problem, rather a jdk issue regarding lambdas:
It seems this is due to the lambda class names contain a /. i.e. com.rits.tests.cloning.Jdk8Class2$$Lambda$1/836514715 Then the classloader replaces / with a dot and tries to load com.rits.tests.cloning.Jdk8Class2$$Lambda$1.836514715 which is not valid. So far I didn't find a work around as the problem is not part of my code.
@kostaskougios , sorry I misunderstood. I thought you meant the objenesis project code could handle that in a better way. Thanks.
Triggered NoClassDefFoundError/ClassNotFoundException
Test Code
package org.lyh.testcode4java.lambda;
import java.time.temporal.Temporal;
import java.util.function.ToLongFunction;
/**
* @author [email protected]
* @date 2018/12/26
*/
public class ParentClass<T extends Temporal> {
protected ToLongFunction<T> getEpochMillis;
public ParentClass(ToLongFunction<T> getEpochMillis) {
this.getEpochMillis = getEpochMillis;
}
}
package org.lyh.testcode4java.lambda;
import com.google.common.base.Function;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author [email protected]
* @date 2018/12/26
*/
public class ChildClass extends ParentClass<ZonedDateTime> {
public ChildClass(DateTimeFormatter dateTimeFormatter) {
super(dt -> dt.toInstant().toEpochMilli());
Function<ZonedDateTime, Integer> getNano = ZonedDateTime::getNano;
Function<ZonedDateTime, Long> toEpochSecond = ZonedDateTime::toEpochSecond;
}
}
package org.lyh.testcode4java.lambda;
import com.rits.cloning.Cloner;
import java.time.format.DateTimeFormatter;
/**
* @author [email protected]
* @date 2018/12/26
*/
public class TestMain {
public static void main(String[] args) {
Cloner cloner = new Cloner();
ChildClass childClass = new ChildClass(DateTimeFormatter.ISO_DATE_TIME);
ChildClass childClass1 = cloner.deepClone(childClass);
}
}
<dependency>
<groupId>uk.com.robust-it</groupId>
<artifactId>cloning</artifactId>
<version>1.9.6</version>
</dependency>
Output :
[Loaded org.lyh.testcode4java.lambda.ParentClass from file:/Users/figo/work/test-code4java/target/classes/]
[Loaded org.lyh.testcode4java.lambda.ChildClass from file:/Users/figo/work/test-code4java/target/classes/]
[Loaded org.lyh.testcode4java.lambda.ChildClass$$Lambda$7/1789447862 from org.lyh.testcode4java.lambda.ChildClass]
[Loaded org.lyh.testcode4java.lambda.ChildClass$$Lambda$8/1289696681 from org.lyh.testcode4java.lambda.ChildClass]
[Loaded org.lyh.testcode4java.lambda.ChildClass$$Lambda$9/1607460018 from org.lyh.testcode4java.lambda.ChildClass]
Exception in thread "main" java.lang.NoClassDefFoundError: org/lyh/testcode4java/lambda/ChildClass$$Lambda$7/1789447862
at org.lyh.testcode4java.lambda.TestMain.main(TestMain.java:15)
Caused by: java.lang.ClassNotFoundException: org.lyh.testcode4java.lambda.ChildClass$$Lambda$7.1789447862
ChildClass$$Lambda$7/1789447862 --> ChildClass$$Lambda$7.1789447862
I saw the '/' in the Class name was replaced with '.'
, but I didn't find the replacement action in the code for Cloning. Is it a JDK bug?
I think this issue is fixed by Objenesis (the version I use is 3.0.1). this is my test code:
public class LambdaTest {
public ArrayList<Integer> list;
public LambdaTest() {
list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
}
public void show() {
list.stream()
.filter(i -> i % 2 == 0)
.forEach(System.out::println);
}
}
public void testLambda() {
LambdaTest l = new LambdaTest();
LambdaTest f = cloner.deepClone(l);
f.show();
}
and output:
clone>class com.rits.tests.cloning.TestJia$LambdaTest
clone>class com.rits.tests.cloning.TestJia$LambdaTest
cloned field>public java.util.ArrayList com.rits.tests.cloning.TestJia$LambdaTest.list -- of class class com.rits.tests.cloning.TestJia$LambdaTest
clone>class com.rits.tests.cloning.TestJia
cloned field>private final com.rits.cloning.Cloner com.rits.tests.cloning.TestJia.cloner -- of class class com.rits.tests.cloning.TestJia
cloned field>final com.rits.tests.cloning.TestJia com.rits.tests.cloning.TestJia$LambdaTest.this$0 -- of class class com.rits.tests.cloning.TestJia$LambdaTest
2
4
@ZhenXiongQian your code doesn't clone any lambda.
I tried v3.2 of objenesis with this test:
public void testLambda() {
Function<ZonedDateTime, Integer> f = ZonedDateTime::getNano;
cloner.deepClone(f);
}
But still fails with
Caused by: java.lang.ClassNotFoundException: com.rits.tests.cloning.TestCloner$$Lambda$54.0x0000000800c24210
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:636)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:182)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:519)
@kostaskougios ,sorry my code is a wrong example.
And I try tu run your lest,. There is a question, why I got a java.lang.NoClassDefFoundError
with the same code that you got java.lang.ClassNotFoundException
.
java.lang.NoClassDefFoundError: com/rits/tests/cloning/TestJia$$Lambda$42/0x0000000800bc97f0
at jdk.internal.reflect.GeneratedSerializationConstructorAccessor2.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at com.rits.cloning.Cloner$CloneObjectCloner.deepClone(Cloner.java:627)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:454)
at com.rits.cloning.Cloner.deepClone(Cloner.java:345)
at com.rits.tests.cloning.TestJia.testLambda2(TestJia.java:104)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at junit.framework.TestCase.runTest(TestCase.java:177)
at junit.framework.TestCase.runBare(TestCase.java:142)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:221)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
@kostaskougios I am confused now.
I use your test code in an new empty project and get the clone library by maven.
Just to clarify @ZhenXiongQian , the full exception stacktrace:
java.lang.NoClassDefFoundError: com/rits/tests/cloning/TestCloner$$Lambda$46/0x0000000800c11230
at jdk.internal.reflect.GeneratedSerializationConstructorAccessor2.newInstance(Unknown Source)
at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at com.rits.cloning.Cloner$CloneObjectCloner.deepClone(Cloner.java:622)
at com.rits.cloning.Cloner.cloneInternal(Cloner.java:449)
at com.rits.cloning.Cloner.deepClone(Cloner.java:340)
at com.rits.tests.cloning.TestCloner.testLambda(TestCloner.java:924)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at junit.framework.TestCase.runTest(TestCase.java:177)
at junit.framework.TestCase.runBare(TestCase.java:142)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.lang.ClassNotFoundException: com.rits.tests.cloning.TestCloner$$Lambda$46.0x0000000800c11230
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:636)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:182)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:519)
... 26 more
Process finished with exit code 255
So NoClassDefFoundError which was caused by ClassNotFoundException
why it is not report error in the case of this time
@ZhenXiongQian hmm not sure. Which java & cloner version are you using?
@kostaskougios
version:
test code:
result:
@ZhenXiongQian indeed for adopt-open-jdk9 it works correctly. It seems this jdk instantiates functions in a different way than the others