Как динамически загружать подкласс базового класса при использовании оператора new - PullRequest
0 голосов
/ 06 сентября 2018

У меня есть файл TestInstrumentation.java , как показано ниже -

public class TestInstrumentation {
    public static void main(String args[]) throws InterruptedException {
        Lion l = new Lion();
        l.runLion();
    }
}

Существует класс Lion.java , как показано ниже -

public class Lion {
    String str = "abc";
    public void runLion() throws InterruptedException {
        System.out.println("Lion is going to run........");
    }
}

А есть еще один класс LionExt.java следующим образом -

public class LionExt extends Lion {
    String str = "xyz";
    String str1 = "xyz";
    @Override
    public void runLion() throws InterruptedException {
        //super.runLion();
        System.out.println("LionExt is going to run........" + str + "--" + str1 + "++");
        sayHello();
    }

    public void sayHello() {
        System.out.println("OK");
    }
}

Я хочу, чтобы строка Lion l = new Lion(); в TestInstrumentation.java возвращала экземпляр LionExt вместо Lion без изменения исходного кода TestInstrumentation.java

Это означает, что мне нужно использовать некоторую библиотеку для динамической загрузки соответствующего подкласса класса Test вместо самого класса, который создает новый экземпляр.

Для этого я использовал API инструментария Java и API Javaassist, и мой класс преобразователя Instrumentation выглядит следующим образом -

public class DurationTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className,
        Class classBeingRedefined, ProtectionDomain protectionDomain,
        byte[] classfileBuffer) throws IllegalClassFormatException {
    byte[] byteCode = classfileBuffer;

    if (className.equals("com/javapapers/java/instrumentation/Lion")) {
        System.out.println("Instrumenting......");
        try {
            ClassPool classPool = ClassPool.getDefault();
            CtClass ctClassold = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
            CtClass ctClassnew = classPool.getCtClass("com.javapapers.java.instrumentation.LionExt");
            CtField[] fields = ctClassnew.getDeclaredFields();
            for(CtField field : fields) {
                if(!Arrays.asList(Arrays.stream(ctClassold.getDeclaredFields()).map(m -> m.getName()).toArray()).contains(field.getName()))
                    ctClassold.getClassFile2().addField2(field.getFieldInfo2());
            }
            CtMethod[] methods = ctClassnew.getDeclaredMethods();
            for (CtMethod method : methods) {
                if(Arrays.asList(Arrays.stream(ctClassold.getDeclaredMethods()).map(m -> m.getName()).toArray()).contains(method.getName()))
                    ctClassold.getDeclaredMethod(method.getName()).setBody(method, new ClassMap());
                else ctClassold.getClassFile2().addMethod2(method.getMethodInfo2());
            }
            byteCode = ctClassold.toBytecode();
            ctClassold.detach();
            System.out.println("Instrumentation complete.");
        } catch (Throwable ex) {
            System.out.println("Exception: " + ex);
            ex.printStackTrace();
        }
    }
    return byteCode;
    }
}

И я добавил преобразователь в методе premain в классе агента -

public class DurationAgent {
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Executing premain.........");
        inst.addTransformer(new DurationTransformer());
    }
}

Все, что я сделал в методе переопределенного преобразования, - это скопировал все методы и поля подкласса в суперкласс, и ниже приведен вывод файла -

Executing premain.........
Instrumenting......
Instrumentation complete.
LionExt is going to run........abc--null++
OK

Так это работает! кроме не совсем!

Вы видите, что перезапись суперкласса с помощью тела метода подкласса не является хорошей идеей, и вы не можете использовать вызов super () ни в одном из методов подкласса, а значения полей не вступают в силу.

Есть ли другой способ сделать то, что я хочу, используя эту или любую другую библиотеку?

...