Skip to content

Instantly share code, notes, and snippets.

@ChristianSchwarz
Created April 29, 2016 12:49
Show Gist options
  • Select an option

  • Save ChristianSchwarz/1b597889026ee0701ff3d8c870c5320c to your computer and use it in GitHub Desktop.

Select an option

Save ChristianSchwarz/1b597889026ee0701ff3d8c870c5320c to your computer and use it in GitHub Desktop.
ByteBuddy+JavaAssist
package agh;
public final class MyFinalType implements Processor<String> {
@Override
public final void process(String message) {
};
}
package agh;
public interface Processor<T> {
void process(T message);
}
package agh;
import static java.lang.Thread.currentThread;
import static javassist.Modifier.FINAL;
import static net.bytebuddy.matcher.ElementMatchers.named;
import java.io.IOException;
import java.util.concurrent.Callable;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;
import com.esotericsoftware.reflectasm.FieldAccess;
import com.esotericsoftware.reflectasm.MethodAccess;
public class Rewrite implements Callable<Void> {
public MyFinalType t;
@Override
public Void call() throws Exception {
ClassLoader cl = currentThread().getContextClassLoader();
Class<?> myFinalType = removeFinal("agh.MyFinalType", cl);
MyFinalType p;
p = (MyFinalType) new ByteBuddy()//
.subclass(myFinalType)//
.method(named("process"))//
.intercept(MethodDelegation.to(TargetImpl.class))//
.make()//
.load(cl, ClassLoadingStrategy.Default.WRAPPER)//
.getLoaded()//
.newInstance();
FieldAccess f = FieldAccess.get(Rewrite.class);
int fieldIndex = f.getIndex("t");
f.set(this, fieldIndex, p);
return null;
}
public static void main(String[] args) throws Exception {
new Rewrite().call();
}
private static <T> Class<T> removeFinal(String classname, ClassLoader classLoader) throws ClassNotFoundException {
CtClass ctClass = getCtClass(classname, classLoader);
removeFinal(ctClass);
removeFinal(ctClass.getMethods());
return load(ctClass, classLoader);
}
private static void removeFinal(CtClass ctClass) {
int modifiers = ctClass.getModifiers();
modifiers &= ~FINAL;
ctClass.setModifiers(modifiers);
}
private static void removeFinal(CtMethod[] methods) {
for (CtMethod m : methods) {
int modifiers = m.getModifiers();
modifiers &= ~FINAL;
m.setModifiers(modifiers);
}
}
private static CtClass getCtClass(String classname, ClassLoader classLoader) throws ClassNotFoundException {
ClassPool pool = ClassPool.getDefault();
CtClass ctClass;
try {
ctClass = pool.get(classname);
} catch (NotFoundException e) {
throw new ClassNotFoundException("Class not found '" + classname + "' using classloader " + classLoader, e);
}
return ctClass;
}
private static <T> Class<T> load(CtClass ctClass, ClassLoader classLoader) {
try {
return (Class<T>) ctClass.toClass(classLoader, null);
} catch (CannotCompileException e) {
throw new IllegalStateException(e);
}
}
public static class TargetImpl {
public static void process(Object text) {
System.out.println(text);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment