Как сделать абстрактный класс неабстрактным с Javassist? - PullRequest
2 голосов
/ 08 ноября 2011

В небольшом каркасе, который я создаю, я хотел бы изменить некоторые абстрактные классы на неабстрактные с помощью Javassist.Я уже преобразовал все абстрактные методы в неабстрактные, реализующие динамически сгенерированный код, который мне нужен.Но мне пока не удалось сделать класс неабстрактным.Я попробовал нечто похожее на это:

Допустим, c - это класс, который я хотел бы сделать неабстрактным.Поэтому я написал:

public void instrument(Class c) {
    ...//some ignored exception management
    CtClass ctClass = ClassPool.getDefault().get(c.getName());
    ctClass.setModifiers(c.getModifiers() & ~Modifier.ABSTRACT);  
    return ctClass.toClass().newInstance();
}

Тем не менее, вызов:

ctClass.toClass();

поднимает следующее CannotCompileException:

"attempted  duplicate class definition for name: <class_name>."

Это потому, чтокласс уже загружен, так как я вызываю его метод getName.Мне кажется, это единственный механизм, который я должен получить CtClass из существующего класса, но, пожалуйста, кто-нибудь, скажите мне, если это не правильно.Жесткое кодирование имени класса вместо вызова его метода getName далеко не идеальное решение, учитывая, что мне нужно применить эту процедуру ко многим классам.

Любой обходной путь для этого?Если это вообще невозможно, я буду динамически генерировать новый класс, который расширяет абстрактный класс, реализует его конструкторы и абстрактный метод всех его предков (немного сложнее, поэтому я был бы очень рад, если бы мне удалось просто сделатьвместо этого оригинальный класс, не являющийся абстратом).

Ответы [ 2 ]

2 голосов
/ 08 ноября 2011

Вы пытались создать расширяющий класс, а не менять существующий класс?Поэтому создайте класс, реализуйте все методы и используйте setSuperClass(), чтобы расширить его абстрактный класс.

1 голос
/ 25 ноября 2011

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

Одним из вариантов может быть небольшая хитрость загрузчика классов: создайте новый загрузчик классов, в который не загружены ваши существующие классы (родительский класс является системным загрузчиком классов), и загрузите через него Javassist (используйте CtClass.toClass() метод это принимает ClassLoader аргумент ).

Как и предполагалось, может быть лучший способ достичь вашей цели, а создание подклассов может быть лучшим дизайном. Использование интерфейсов вместо абстрактных классов вариант? Если это так, то динамические прокси также являются опцией, их преимущество в том, что вам не нужны сторонние библиотеки для их создания.

...