Skip to content

Commit

Permalink
fix(newinstance): forces usage of the newest version of the class
Browse files Browse the repository at this point in the history
  • Loading branch information
tdurieux authored and monperrus committed Oct 31, 2016
1 parent d8a536d commit 7e6f111
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 20 deletions.
35 changes: 26 additions & 9 deletions src/main/java/spoon/support/reflect/declaration/CtClassImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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}.
*
Expand Down Expand Up @@ -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);
}
}
}
}
50 changes: 39 additions & 11 deletions src/test/java/spoon/test/compilation/CompilationTest.java
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {

Expand Down Expand Up @@ -106,6 +109,31 @@ public void compileTest() throws Exception {
Assert.assertEquals(42, m.invoke(aClass.newInstance()));
}

@Test
public void testNewInstanceFromExistingClass() throws Exception {
CtClass<Bar> barCtType = (CtClass<Bar>) ModelUtils.buildClass(Bar.class);
CtReturn<Integer> 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
Expand Down
11 changes: 11 additions & 0 deletions src/test/java/spoon/test/compilation/testclasses/Bar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package spoon.test.compilation.testclasses;

public class Bar implements IBar {

@Override
public int m() {
return 1;
}
}

class FooEx extends RuntimeException {}
8 changes: 8 additions & 0 deletions src/test/java/spoon/test/compilation/testclasses/IBar.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package spoon.test.compilation.testclasses;

/**
* Created by thomas on 28/10/16.
*/
public interface IBar {
int m();
}

0 comments on commit 7e6f111

Please sign in to comment.