Как переопределить загруженные классы из скомпилированных файлов классов - PullRequest
0 голосов
/ 04 июля 2019

Я пытаюсь переопределить существующий класс (называемый Module) в моем коде новыми версиями во время выполнения. Новые версии представлены в виде скомпилированных файлов классов, которые сохраняются в каком-либо каталоге. Есть ли способ сделать это с помощью ByteBuddy?

Я пытался использовать ByteArrayClassLoader для определения класса из файла классов. Определенный класс, кажется, имеет обновленные методы. Я проверил это, пройдя через методы определенного класса и вызвав их (то есть метод process, который возвращает некоторую строку). Однако, когда я пытаюсь использовать ByteBuddy.redefine (...), я получаю сообщение об ошибке «Не удалось найти файл класса для some.package.Module». Я попытался передать ClassFileLocator, который я использовал, чтобы найти файл класса для новой версии. но я все еще получаю эту ошибку.

    public void redefine() throws Exception {

        String path = System.getProperty("user.dir")+"/someDir";

        Map<String, byte[]> map = new HashMap<>();
        ClassFileLocator cfl = new ForFolder(new File(path));
        byte[] clazzBytes = cfl.locate("Module").resolve();
        map.put(clazz.getName(), clazzBytes);

        ByteArrayClassLoader bac = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, false, map);

        Class<?> replacementClass = bac.defineClass(clazz.getName(), clazzBytes);

        for (Method m : replacementClass.getMethods()) {
            if (m.getName().equals("process")) {
                System.out.println((String) m.invoke(replacementClass.newInstance(), "invoked from new instance"));
            }
        }
        AgentBuilder agentBuilder = new AgentBuilder.Default()
            .with(new Listener.Filtering(
                new StringMatcher("bytebuddy_instrumentation.Module", Mode.CONTAINS),
                Listener.StreamWriting.toSystemOut()
            ))
            .with(RedefinitionStrategy.REDEFINITION)
            .with(Default.REDEFINE)
            .disableClassFormatChanges()
            .type(ElementMatchers.is(clazz))
            .transform((builder, typeDescription, classLoader, module) ->
                new ByteBuddy()
                    .redefine(replacementClass, cfl)
                    .name(clazz.getName()));

        this.resetter = agentBuilder.installOnByteBuddyAgent();
    }

Переопределение не выполняется с текущим кодом из-за java.lang.IllegalStateException: Could not locate class file for some.package.Module

1 Ответ

0 голосов
/ 05 июля 2019

Если вы просто хотите заменить другой класс другим представлением байтового кода, зачем вам использовать Byte Buddy?

Вы можете заменить класс на Instrumentation API, используя redefineClass, где вы можете напрямую передать замену.

Ошибка, вероятно, связана с использованием вами стратегии REDEFINE, в которой Байту Бадди нужно найти файлы классов всех классов. Вероятно, было бы лучше использовать RETRANSFORM. Однако невозможно сказать наверняка без трассировки стека.

...