use of org.springsource.loaded.test.infra.Result in project spring-loaded by spring-projects.
the class MethodInvokerRewriterTests method rewriteInvokeStatic5.
/**
* Reloading target where the method to call has been deleted.
* <p>
* Here is what happens in the Java case (class A calling static method B.foo that has been deleted):
*
* <pre>
* Exception in thread "main" java.lang.NoSuchMethodError: B.foo()V
* at A.main(A.java:3)
* </pre>
*/
@Test
public void rewriteInvokeStatic5() throws Exception {
TypeRegistry typeRegistry = getTypeRegistry("tgt.SimpleClass");
ReloadableType callee = typeRegistry.addType("tgt.SimpleClass", loadBytesForClass("tgt.SimpleClass"));
byte[] callerbytes = loadBytesForClass("tgt.StaticCaller");
byte[] rewrittenBytes = MethodInvokerRewriter.rewrite(typeRegistry, callerbytes);
Class<?> callerClazz = loadit("tgt.StaticCaller", rewrittenBytes);
// run the original
Result result = runUnguarded(callerClazz, "run");
assertEquals(123, result.returnValue);
// new version of SimpleClass where target static method has been removed
callee.loadNewVersion("5", retrieveRename("tgt.SimpleClass", "tgt.SimpleClass005"));
try {
result = runUnguarded(callerClazz, "run");
Assert.fail();
} catch (InvocationTargetException ite) {
Throwable t = ite.getCause();
NoSuchMethodError icce = (NoSuchMethodError) t;
assertEquals("SimpleClass.toInt(Ljava/lang/String;)I", icce.getMessage());
}
}
use of org.springsource.loaded.test.infra.Result in project spring-loaded by spring-projects.
the class MethodInvokerRewriterTests method rewriteInvokeStatic2.
// @Test
// public void rewriteMethodAccessesGetIntNonStatic() throws Exception {
// TypeRegistry typeRegistry = TypeRegistry.getTypeRegistryFor(binLoader);
// configureForTesting(typeRegistry, "data.Apple");
//
// byte[] caller = retrieveBytesForClass("data.Orange");
// checkMethod(caller, "accessFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " GETFIELD data/Apple.intFieldI\n" +
// " ISTORE 1\n" +
// " L1\n" +
// " ILOAD 1\n" +
// " IRETURN\n" +
// " L2\n");
//
// byte[] rewrittenBytes = MethodCallAndFieldAccessRewriter.rewrite(typeRegistry, caller);
// checkMethod(rewrittenBytes, "accessFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " LDC intField\n" +
// " LDC I\n" +
// " INVOKEVIRTUAL data/Apple.r$get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;\n" +
// " CHECKCAST java/lang/Integer\n" +
// " INVOKEVIRTUAL java/lang/Integer.intValue()I\n" +
// " ISTORE 1\n" +
// " L1\n" +
// " ILOAD 1\n" +
// " IRETURN\n" +
// " L2\n");
//
// }
//
// @Test
// public void rewriteMethodAccessesGetIntStatic() throws Exception {
// TypeRegistry typeRegistry = TypeRegistry.getTypeRegistryFor(binLoader);
// // Configure it directly such that data.Apple is considered reloadable
// configureForTesting(typeRegistry, "data.Apple");
// typeRegistry.addType("data.Apple", retrieveBytesForClass("data.Apple"));
//
// byte[] caller = retrieveBytesForClass("data.Orange");
// checkMethod(caller, "getStaticFieldOnApple",
// " L0\n" +
// " GETSTATIC data/Apple.staticIntFieldI\n" +
// " IRETURN\n" +
// " L1\n");
//
// byte[] rewrittenBytes = MethodCallAndFieldAccessRewriter.rewrite(typeRegistry, caller);
// checkMethod(rewrittenBytes, "getStaticFieldOnApple",
// " L0\n" +
// " LDC staticIntField\n" +
// " LDC I\n" +
// " INVOKESTATIC data/Apple.r$gets(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;\n" +
// " CHECKCAST java/lang/Integer\n" +
// " INVOKEVIRTUAL java/lang/Integer.intValue()I\n" +
// " IRETURN\n" +
// " L1\n");
//
// Class<?> callerClass = loadit("data.Orange", rewrittenBytes);
// Object o = callerClass.newInstance();
// runOnInstance(callerClass, o, "setStaticFieldOnApple");
// Result result = runOnInstance(callerClass, o, "getStaticFieldOnApple");
// assertEquals(35, result.returnValue);
//
// // calling it again on a different instance (static so should give same result)
// result = runOnInstance(callerClass, callerClass.newInstance(), "getStaticFieldOnApple");
// assertEquals(35, result.returnValue);
// }
//
// @Test
// public void rewriteMethodAccessesSetIntNonStatic() throws Exception {
// TypeRegistry typeRegistry = TypeRegistry.getTypeRegistryFor(binLoader);
// // Configure it directly such that data.Apple is considered reloadable
// configureForTesting(typeRegistry, "data.Apple");
// typeRegistry.addType("data.Apple", retrieveBytesForClass("data.Apple"));
//
// byte[] caller = retrieveBytesForClass("data.Orange");
// checkMethod(caller, "setFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " BIPUSH 35\n" +
// " PUTFIELD data/Apple.intFieldI\n" +
// " L1\n" +
// " RETURN\n" +
// " L2\n");
//
// byte[] rewrittenBytes = MethodCallAndFieldAccessRewriter.rewrite(typeRegistry, caller);
// checkMethod(rewrittenBytes, "setFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " BIPUSH 35\n" +
// " INVOKESTATIC java/lang/Integer.valueOf(I)Ljava/lang/Integer;\n" +
// " LDC intField\n" +
// " LDC I\n" +
// " INVOKEVIRTUAL data/Apple.r$set(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V\n" +
// " L1\n" +
// " RETURN\n" +
// " L2\n");
//
// checkMethod(caller, "accessFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " GETFIELD data/Apple.intFieldI\n" +
// " ISTORE 1\n" +
// " L1\n" +
// " ILOAD 1\n" +
// " IRETURN\n" +
// " L2\n");
//
// checkMethod(rewrittenBytes, "accessFieldOnApple",
// " L0\n" +
// " ALOAD 0\n" +
// " GETFIELD data/Orange.appleLdata/Apple;\n" +
// " LDC intField\n" +
// " LDC I\n" +
// " INVOKEVIRTUAL data/Apple.r$get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Object;\n" +
// " CHECKCAST java/lang/Integer\n" +
// " INVOKEVIRTUAL java/lang/Integer.intValue()I\n" +
// " ISTORE 1\n" +
// " L1\n" +
// " ILOAD 1\n" +
// " IRETURN\n" +
// " L2\n");
//
// Class<?> callerClass = loadit("data.Orange", rewrittenBytes);
// Object o = callerClass.newInstance();
// runOnInstance(callerClass, o, "setFieldOnApple");
// Result result = runOnInstance(callerClass, o, "accessFieldOnApple");
// assertEquals(35, result.returnValue);
//
// // and again on a different instance - should not be set this time
// result = runOnInstance(callerClass, callerClass.newInstance(), "accessFieldOnApple");
// assertEquals(0, result.returnValue);
// }
// change GETFIELD <RELOADABLETYPE>.name<TYPE>
// Change it to use a field accessor
// we need to allow for calls to a field that gets removed
// and to a field that is being added
// Apple.s$get("intField","I") (will return a boxed Integer)
// (with an unbox on the client side - as the requested type is int)
// TODO review optimization of having static 'pack' methods with a variety of input params, returning an Object[] - will save a bunch of instructions
// TODO review optimization of calling to a generated method (synthetic) that can do the packing (so synthetic has same params/return as invokestatic site)
// this second optimization would greatly reduce generated code
// TODO review optimization: extending 2 could even pull the invokestatic of anyChanges out into that helper too
/**
* Rewrite of a simple INVOKESTATIC call - change the callee (to exercise the dispatching through the interface).
* This checks the behaviour of the TypeRegistry.anyChanges(int, String) method which determines whether we have to
* dispatch to something different due to a reload.
*/
@Test
public void rewriteInvokeStatic2() throws Exception {
TypeRegistry typeRegistry = getTypeRegistry("tgt.SimpleClass");
ReloadableType callee = typeRegistry.addType("tgt.SimpleClass", loadBytesForClass("tgt.SimpleClass"));
byte[] callerbytes = loadBytesForClass("tgt.StaticCaller");
byte[] rewrittenBytes = MethodInvokerRewriter.rewrite(typeRegistry, callerbytes);
Class<?> callerClazz = loadit("tgt.StaticCaller", rewrittenBytes);
// ClassPrinter.print(callee.bytesLoaded);
// run the original
Result result = runUnguarded(callerClazz, "run");
assertEquals(123, result.returnValue);
callerbytes = loadBytesForClass("tgt.StaticCaller002");
callerbytes = ClassRenamer.rename("tgt.StaticCaller002", callerbytes, "tgt.SimpleClass002:tgt.SimpleClass");
rewrittenBytes = MethodInvokerRewriter.rewrite(typeRegistry, callerbytes);
Class<?> callerClazz002 = loadit("tgt.StaticCaller002", rewrittenBytes);
callee.loadNewVersion("2", retrieveRename("tgt.SimpleClass", "tgt.SimpleClass002"));
result = runUnguarded(callerClazz002, "run2");
assertEquals("456", result.returnValue);
}
use of org.springsource.loaded.test.infra.Result in project spring-loaded by spring-projects.
the class MethodInvokerRewriterTests method callingMethodIntroducedLaterReturningPrimitiveChar.
@Test
public void callingMethodIntroducedLaterReturningPrimitiveChar() throws Exception {
TypeRegistry typeRegistry = TypeRegistry.getTypeRegistryFor(binLoader);
// Configure it directly such that data.Apple is considered reloadable
configureForTesting(typeRegistry, "data.Apple");
ReloadableType apple = typeRegistry.addType("data.Apple", loadBytesForClass("data.Apple"));
byte[] callerbytes = loadBytesForClass("data.Orange002");
callerbytes = ClassRenamer.rename("data.Orange", callerbytes, "data.Apple002:data.Apple");
byte[] rewrittenBytes = MethodInvokerRewriter.rewrite(typeRegistry, callerbytes);
Class<?> callerClazz = loadit("data.Orange", rewrittenBytes);
runExpectNoSuchMethodException(callerClazz, "callAppleRetChar", new Object[] { (char) 'a' });
// Load a version of Apple that does define that method
apple.loadNewVersion("002", retrieveRename("data.Apple", "data.Apple002"));
Result result = runUnguarded(callerClazz, "callAppleRetChar", new Object[] { (char) 'a' });
assertEquals('b', result.returnValue);
}
use of org.springsource.loaded.test.infra.Result in project spring-loaded by spring-projects.
the class MethodInvokerRewriterTests method rewriteInvokeStatic4.
/**
* Reloading target with a modified static method.
*/
@Test
public void rewriteInvokeStatic4() throws Exception {
TypeRegistry typeRegistry = getTypeRegistry("tgt.SimpleClass");
ReloadableType callee = typeRegistry.addType("tgt.SimpleClass", loadBytesForClass("tgt.SimpleClass"));
byte[] callerbytes = loadBytesForClass("tgt.StaticCaller");
byte[] rewrittenBytes = MethodInvokerRewriter.rewrite(typeRegistry, callerbytes);
Class<?> callerClazz = loadit("tgt.StaticCaller", rewrittenBytes);
// run the original
Result result = runUnguarded(callerClazz, "run");
assertEquals(123, result.returnValue);
// new version of SimpleClass always returns 256
callee.loadNewVersion("4", retrieveRename("tgt.SimpleClass", "tgt.SimpleClass004"));
result = runUnguarded(callerClazz, "run");
assertEquals(256, result.returnValue);
}
use of org.springsource.loaded.test.infra.Result in project spring-loaded by spring-projects.
the class SpringLoadedTests method runConstructor.
public Result runConstructor(Class<?> clazz, String paramDescriptor, Object... params) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
PrintStream oldo = System.out;
PrintStream olde = System.err;
Object result = null;
ByteArrayOutputStream oso = new ByteArrayOutputStream();
ByteArrayOutputStream ose = new ByteArrayOutputStream();
try {
if (capture) {
System.setOut(new PrintStream(oso));
System.setErr(new PrintStream(ose));
}
Constructor<?>[] cs = clazz.getConstructors();
Constructor<?> c = null;
for (Constructor<?> ctor : cs) {
Class<?>[] paramClazzes = ctor.getParameterTypes();
String toParamDescriptorString = toParamDescriptorString(paramClazzes);
// System.out.println(toParamDescriptorString + "<<");
if (paramDescriptor.equals(toParamDescriptorString)) {
c = ctor;
break;
}
}
if (c == null) {
Assert.fail("Invocation failure: could not find constructor with param descriptor " + paramDescriptor + " on type '" + clazz.getName());
}
c.setAccessible(true);
result = c.newInstance(params);
} finally {
if (capture) {
System.setOut(oldo);
System.setErr(olde);
}
}
return new Result(result, oso.toString().replace("\r", ""), ose.toString().replace("\r", ""));
}
Aggregations