From 29b014175a6b09310c757e6e5d5da9b8c208d3d9 Mon Sep 17 00:00:00 2001 From: Andy Clement Date: Tue, 30 Apr 2013 13:55:03 -0700 Subject: [PATCH] https://github.com/SpringSource/spring-loaded/issues/6 --- .../src/invokestatic/issue4/AB.java | 5 ++ .../src/invokestatic/issue4/BBBB.java | 9 ++++ .../src/invokestatic/issue4/BBBBB.java | 9 ++++ .../org/springsource/loaded/TypeRegistry.java | 48 ++++++++++++------- .../loaded/test/ReloadableTypeTests.java | 43 +++++++++++++++++ .../loaded/test/SpringLoadedTests.java | 3 +- 6 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 org.springsource.loaded.testdata/src/invokestatic/issue4/AB.java create mode 100644 org.springsource.loaded.testdata/src/invokestatic/issue4/BBBB.java create mode 100644 org.springsource.loaded.testdata/src/invokestatic/issue4/BBBBB.java diff --git a/org.springsource.loaded.testdata/src/invokestatic/issue4/AB.java b/org.springsource.loaded.testdata/src/invokestatic/issue4/AB.java new file mode 100644 index 0000000..4b630ac --- /dev/null +++ b/org.springsource.loaded.testdata/src/invokestatic/issue4/AB.java @@ -0,0 +1,5 @@ +package invokestatic.issue4; + +public class AB extends codeforjar.A { + +} diff --git a/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBB.java b/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBB.java new file mode 100644 index 0000000..7ebbdc4 --- /dev/null +++ b/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBB.java @@ -0,0 +1,9 @@ +package invokestatic.issue4; + +public class BBBB extends codeforjar.A { + + public static String getMessage() { + return getString(); + } + +} diff --git a/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBBB.java b/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBBB.java new file mode 100644 index 0000000..efaaaf9 --- /dev/null +++ b/org.springsource.loaded.testdata/src/invokestatic/issue4/BBBBB.java @@ -0,0 +1,9 @@ +package invokestatic.issue4; + +public class BBBBB extends AB { + + public static String getMessage() { + return getString(); + } + +} diff --git a/org.springsource.loaded/src/main/java/org/springsource/loaded/TypeRegistry.java b/org.springsource.loaded/src/main/java/org/springsource/loaded/TypeRegistry.java index a777ba7..34c744e 100644 --- a/org.springsource.loaded/src/main/java/org/springsource/loaded/TypeRegistry.java +++ b/org.springsource.loaded/src/main/java/org/springsource/loaded/TypeRegistry.java @@ -1118,33 +1118,47 @@ public class TypeRegistry { .getFromLatestByDescriptor(nameAndDescriptor); boolean dispatchThroughDescriptor = false; if (method == null) { - // method has been deleted or is on a supertype + // method has been deleted or is on a supertype. Look for it: + + // TODO this block is based on something below in invokespecial handling but this has some + // fixes in - should they be migrated down below or a common util method constructed? - // Search supertypes - block copied from invokespecialSearch below, TODO could refactor into common util Object dispatcherToUse = null; - ReloadableType nextCandidate = reloadableType.getTypeRegistry().getReloadableType(reloadableType.getTypeDescriptor().getSupertypeName(),false); - boolean found = false; - while (nextCandidate != null) { - MethodMember m = null; - if (nextCandidate.hasBeenReloaded()) { - m = nextCandidate.getLiveVersion().incrementalTypeDescriptor.getFromLatestByDescriptor(nameAndDescriptor); - if (m != null && IncrementalTypeDescriptor.wasDeleted(m)) { - m = null; + String supertypename = reloadableType.getTypeDescriptor().getSupertypeName(); + TypeRegistry reg = reloadableType.getTypeRegistry(); + boolean found = false; + while (supertypename != null) { + ReloadableType nextInHierarchy = reg.getReloadableType(supertypename); + if (nextInHierarchy == null) { + TypeDescriptor td = reg.getDescriptorFor(supertypename); + if (td != null) { + method = td.getByNameAndDescriptor(nameAndDescriptor); + supertypename = td.getSupertypeName(); + } else { + break; + } + } else if (nextInHierarchy.hasBeenReloaded()) { + method = nextInHierarchy.getLiveVersion().incrementalTypeDescriptor.getFromLatestByDescriptor(nameAndDescriptor); + if (method != null && IncrementalTypeDescriptor.wasDeleted(method)) { + method= null; } // ignore catchers because the dynamic __execute method wont have an implementation of them, we should // just keep looking for the real thing - if (m != null && MethodMember.isCatcher(m)) { - m = null; + if (method != null && MethodMember.isCatcher(method)) { + method = null; } } else { - m = nextCandidate.getMethod(nameAndDescriptor); - } - if (m != null) { - dispatcherToUse = reloadableType.getLatestDispatcherInstance(); + // it is reloadable but has not been reloaded + method = nextInHierarchy.getMethod(nameAndDescriptor); + } + if (method != null) { found = true; break; } - nextCandidate = reloadableType.getTypeRegistry().getReloadableType(reloadableType.getTypeDescriptor().getSupertypeName(),false); + // the nextInHierarchy==null case will have already set the supertypename + if (nextInHierarchy != null) { + supertypename = nextInHierarchy.getSlashedSupertypeName(); + } } if (found) { return dispatcherToUse; diff --git a/org.springsource.loaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java b/org.springsource.loaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java index 7948979..7f7754f 100644 --- a/org.springsource.loaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java +++ b/org.springsource.loaded/src/test/java/org/springsource/loaded/test/ReloadableTypeTests.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNull; import org.junit.Test; import org.springsource.loaded.GlobalConfiguration; @@ -229,6 +230,48 @@ public class ReloadableTypeTests extends SpringLoadedTests { r = runUnguarded(B.getClazz(), "getMessage"); assertEquals("String1",(String)r.returnValue); } + + // The supertype is not reloadable,it is in a jar + @Test + public void invokeStaticReloading_gh4_5() throws Exception { + TypeRegistry tr = getTypeRegistry("invokestatic.issue4..*"); + ReloadableType B = tr.addType("invokestatic.issue4.BBBB", loadBytesForClass("invokestatic.issue4.BBBB")); + + Result r = runUnguarded(B.getClazz(), "getMessage"); + assertEquals("Hello",(String)r.returnValue); + + ReloadableType thesuper = B.getSuperRtype(); + assertNull(thesuper); + thesuper = tr.getReloadableType("invokestatic/issue4/subpkg/AAAA"); + assertNull(thesuper); + + B.loadNewVersion(B.bytesInitial); + + r = runUnguarded(B.getClazz(), "getMessage"); + assertEquals("Hello",(String)r.returnValue); + } + + // extra class in the middle: A in jar, subtype AB reloadable, subtype BBBBB reloadable + @Test + public void invokeStaticReloading_gh4_6() throws Exception { + TypeRegistry tr = getTypeRegistry("invokestatic.issue4..*"); + ReloadableType AB = tr.addType("invokestatic.issue4.AB", loadBytesForClass("invokestatic.issue4.AB")); + ReloadableType B = tr.addType("invokestatic.issue4.BBBBB", loadBytesForClass("invokestatic.issue4.BBBBB")); + + Result r = runUnguarded(B.getClazz(), "getMessage"); + assertEquals("Hello",(String)r.returnValue); + + ReloadableType thesuper = B.getSuperRtype(); + System.out.println(thesuper); + assertNull(thesuper); + thesuper = tr.getReloadableType("invokestatic/issue4/subpkg/AAAA"); + assertNull(thesuper); + + B.loadNewVersion(B.bytesInitial); + + r = runUnguarded(B.getClazz(), "getMessage"); + assertEquals("Hello",(String)r.returnValue); + } @Test diff --git a/org.springsource.loaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java b/org.springsource.loaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java index 6a3ded6..b6c2a9d 100644 --- a/org.springsource.loaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java +++ b/org.springsource.loaded/src/test/java/org/springsource/loaded/test/SpringLoadedTests.java @@ -89,6 +89,7 @@ public abstract class SpringLoadedTests implements Constants { protected String TestDataPath = "../org.springsource.loaded.testdata/bin"; protected String GroovyTestDataPath = "../org.springsource.loaded.testdata.groovy/bin"; protected String AspectjrtJar = "../org.springsource.loaded.testdata/aspectjrt.jar"; + protected String CodeJar = "../org.springsource.loaded.testdata/code.jar"; protected String GroovyrtJar = "../org.springsource.loaded.testdata.groovy/groovy-1.8.2.jar"; protected Result result; protected TypeRegistry registry; @@ -97,7 +98,7 @@ public abstract class SpringLoadedTests implements Constants { public void setup() throws Exception { SpringLoadedPreProcessor.disabled = true; NameRegistry.reset(); - binLoader = new TestClassLoader(toURLs(TestDataPath, AspectjrtJar), this.getClass().getClassLoader()); + binLoader = new TestClassLoader(toURLs(TestDataPath, AspectjrtJar,CodeJar), this.getClass().getClassLoader()); } @After