From 7e6f11151b94e1cf027c9c682a212d6819abd611 Mon Sep 17 00:00:00 2001 From: Thomas Durieux Date: Mon, 31 Oct 2016 13:11:41 +0100 Subject: [PATCH] fix(newinstance): forces usage of the newest version of the class --- .../reflect/declaration/CtClassImpl.java | 35 +++++++++---- .../test/compilation/CompilationTest.java | 50 +++++++++++++++---- .../test/compilation/testclasses/Bar.java | 11 ++++ .../test/compilation/testclasses/IBar.java | 8 +++ 4 files changed, 84 insertions(+), 20 deletions(-) create mode 100644 src/test/java/spoon/test/compilation/testclasses/Bar.java create mode 100644 src/test/java/spoon/test/compilation/testclasses/IBar.java diff --git a/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java b/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java index 06bdd9d1403..54b113a42f4 100644 --- a/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java +++ b/src/main/java/spoon/support/reflect/declaration/CtClassImpl.java @@ -16,14 +16,6 @@ */ package spoon.support.reflect.declaration; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; - import spoon.SpoonException; import spoon.SpoonModelBuilder.InputType; import spoon.reflect.code.CtCodeElement; @@ -44,6 +36,16 @@ import spoon.support.reflect.eval.VisitorPartialEvaluator; import spoon.support.util.SignatureBasedSortedSet; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; + /** * The implementation for {@link spoon.reflect.declaration.CtClass}. * @@ -251,10 +253,25 @@ public T newInstance() { try { JDTBasedSpoonCompiler spooner = new JDTBasedSpoonCompiler(getFactory()); spooner.compile(InputType.CTTYPES); // compiling the types of the factory - Class klass = new URLClassLoader(new URL[] { spooner.getBinaryOutputDirectory().toURL() }).loadClass(getQualifiedName()); + Class klass = new NewInstanceClassloader(spooner.getBinaryOutputDirectory()).loadClass(getQualifiedName()); return (T) klass.newInstance(); } catch (Exception e) { throw new SpoonException(e); } } + + private class NewInstanceClassloader extends URLClassLoader { + NewInstanceClassloader(File binaryOutputDirectory) throws MalformedURLException { + super(new URL[] { binaryOutputDirectory.toURL()}); + } + + @Override + public Class loadClass(String s) throws ClassNotFoundException { + try { + return findClass(s); + } catch (Exception e) { + return super.loadClass(s); + } + } + } } diff --git a/src/test/java/spoon/test/compilation/CompilationTest.java b/src/test/java/spoon/test/compilation/CompilationTest.java index bb4b9993a05..ad979905224 100644 --- a/src/test/java/spoon/test/compilation/CompilationTest.java +++ b/src/test/java/spoon/test/compilation/CompilationTest.java @@ -1,19 +1,8 @@ package spoon.test.compilation; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.List; - import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; import org.junit.Assert; import org.junit.Test; - import spoon.Launcher; import spoon.compiler.SpoonCompiler; import spoon.reflect.code.BinaryOperatorKind; @@ -30,6 +19,20 @@ import spoon.reflect.visitor.filter.TypeFilter; import spoon.support.compiler.jdt.FileCompiler; import spoon.support.compiler.jdt.JDTBasedSpoonCompiler; +import spoon.test.compilation.testclasses.Bar; +import spoon.test.compilation.testclasses.IBar; +import spoon.testing.utils.ModelUtils; + +import java.io.File; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class CompilationTest { @@ -106,6 +109,31 @@ public void compileTest() throws Exception { Assert.assertEquals(42, m.invoke(aClass.newInstance())); } + @Test + public void testNewInstanceFromExistingClass() throws Exception { + CtClass barCtType = (CtClass) ModelUtils.buildClass(Bar.class); + CtReturn m = barCtType.getMethod("m").getBody().getStatement(0); + // we cannot use Bar because it causes a runtime cast exception (2 different Bar from different classloader) + IBar bar = barCtType.newInstance(); + int value = bar.m(); + assertEquals(1, value); + + // change the return value + m.setReturnedExpression(m.getFactory().Code().createLiteral(2)); + + bar = barCtType.newInstance(); + value = bar.m(); + assertEquals(2, value); + + m.replace(m.getFactory().Code().createCodeSnippetStatement("throw new FooEx()")); + try { + bar = barCtType.newInstance(); + value = bar.m(); + fail(); + } catch (Exception ignore) {} + + } + @Test public void testNewInstance() throws Exception { // contract: a ctclass can be instantiated, and each modification results in a new valid object diff --git a/src/test/java/spoon/test/compilation/testclasses/Bar.java b/src/test/java/spoon/test/compilation/testclasses/Bar.java new file mode 100644 index 00000000000..53b848f7ad8 --- /dev/null +++ b/src/test/java/spoon/test/compilation/testclasses/Bar.java @@ -0,0 +1,11 @@ +package spoon.test.compilation.testclasses; + +public class Bar implements IBar { + + @Override + public int m() { + return 1; + } +} + +class FooEx extends RuntimeException {} \ No newline at end of file diff --git a/src/test/java/spoon/test/compilation/testclasses/IBar.java b/src/test/java/spoon/test/compilation/testclasses/IBar.java new file mode 100644 index 00000000000..e89c51b1efb --- /dev/null +++ b/src/test/java/spoon/test/compilation/testclasses/IBar.java @@ -0,0 +1,8 @@ +package spoon.test.compilation.testclasses; + +/** + * Created by thomas on 28/10/16. + */ +public interface IBar { + int m(); +}