package de.take_weiland.mods.commons.internal.transformers;
import de.take_weiland.mods.commons.asm.info.ClassInfo;
import de.take_weiland.mods.commons.net.ModPacket;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import java.lang.reflect.Constructor;
import static org.objectweb.asm.Opcodes.*;
/**
* @author diesieben07
*/
public final class ModPacketCstrAdder extends ClassVisitor {
public static final boolean isNeeded;
static {
boolean hasValidReflFact;
try {
Class<?> reflFactory = Class.forName("sun.reflect.ReflectionFactory");
reflFactory.getDeclaredMethod("newConstructorForSerialization", Class.class, Constructor.class);
reflFactory.getDeclaredMethod("getConstructorAccessor", Constructor.class);
hasValidReflFact = true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
hasValidReflFact = false;
}
isNeeded = !hasValidReflFact;
}
public ModPacketCstrAdder(ClassVisitor cv) {
super(ASM4, cv);
}
private boolean applicable;
private String superClass;
private boolean foundDfltCstr = false;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
this.superClass = superName;
if (superName == null || superName.equals("java/lang/Object")) {
applicable = false;
} else if (superName.equals("de/take_weiland/mods/commons/net/ModPacket")) {
// fast path for direct inheritors
applicable = true;
} else {
applicable = ClassInfo.of(ModPacket.class).isAssignableFrom(ClassInfo.of(superName));
}
if (applicable) {
access = access & ~(ACC_PRIVATE | ACC_PROTECTED) | ACC_PUBLIC;
}
super.visit(version, access, name, signature, superName, interfaces);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (name.equals("<init>") && desc.equals(Type.getMethodDescriptor(Type.VOID_TYPE))) {
foundDfltCstr = true;
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
@Override
public void visitEnd() {
if (applicable && !foundDfltCstr) {
MethodVisitor mv = super.visitMethod(ACC_PUBLIC, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE), null, null);
if (mv != null) {
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", Type.getMethodDescriptor(Type.VOID_TYPE));
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
super.visitEnd();
}
}