Перестановка байтов в сравнении с подклассом и неправильным именем / NoClassDefFoundError в OSGi - PullRequest
2 голосов
/ 14 октября 2019

Я пытаюсь разработать совет, который оборачивает фактический вызов метода. Вот как я объявил мой перехватчик:

public class SecurityInterceptor() {

    @RuntimeType
    public Object intercept(
        @SuperCall Callable<Object> supercall, 
        @This Object target, 
        @Origin Method method, 
        @AllArguments Object[] args) {  

        // Check args and annotations ...       

        Object obj = supercall.call();

        // use Spring SPEL to post-process obj content ...
    }
}

Перехватчик регистрируется следующим образом:

byte[] woven = new ByteBuddy().subclass(type)
    .method(ElementMatchers.isAnnotatedWith(Secured.class))
    .intercept(MethodDelegation.to(new SecurityInterceptor()))
    .make().getBytes();

, где переплетенный байтовый массив управляется через механизм WeavingHook / WovenClass OSGi.

Как только загруженный класс загружается, я получаю следующее исключение:

java.lang.NoClassDefFoundError: com/contoso/users/service/provider/UsersServiceImpl (wrong name: com/contoso/users/service/provider/UsersServiceImpl$ByteBuddy$q3pXZ5KY)
    at java.lang.ClassLoader.defineClass1(Native Method) ~[?:?]
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[?:?]
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.defineClass(BundleWiringImpl.java:2410) ~[?:?]
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.findClass(BundleWiringImpl.java:2194) ~[?:?]
    at org.apache.felix.framework.BundleWiringImpl.findClassOrResourceByDelegation(BundleWiringImpl.java:1607) ~[?:?]
    at org.apache.felix.framework.BundleWiringImpl.access$200(BundleWiringImpl.java:80) ~[?:?]
    at org.apache.felix.framework.BundleWiringImpl$BundleClassLoader.loadClass(BundleWiringImpl.java:2053) ~[?:?]
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:?]
    at org.apache.felix.framework.Felix.loadBundleClass(Felix.java:1927) ~[?:?]
    at org.apache.felix.framework.BundleImpl.loadClass(BundleImpl.java:978) ~[?:?]

Если я использую метод rebase вместо subclass и удаляю @SuperCall Callable<Object> supercall аргумент, вызывается перехватчик.

Эта ошибка появляется только тогда, когда я применяю перехватчик в OSGi: та же процедура отлично работает в тестах vanilla java junit, где я изменяю классы следующим образом:

<T> T loadTestClass(Class<T> clazz) throws Exception {
    return new ByteBuddy()
              .subclass(clazz)
              .method(ElementMatchers.isAnnotatedWith(Secured.class))        
              .intercept(MethodDelegation.to(securityInterceptor))
              .make()
              .load(getClass().getClassLoader())
              .getLoaded()
              .newInstance();
}

Есть идеи, как бороться с этой NoClassDefFoundError / неправильным именем ошибка?

1 Ответ

1 голос
/ 14 октября 2019

Реализации загрузчика классов OSGi обычно используют метод ClassLoader.defineClass, который принимает ожидаемое имя класса в качестве аргумента: например, https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/ClassLoader.html#defineClass(java.lang.String,byte%5B%5D,int,int). При предоставлении ожидаемого имени класса загрузчик класса требует, чтобы определяемый класс имел свое имясоответствует ожидаемое имя класса. Это хорошая проверка работоспособности.

Так что, если загрузчик классов определяет класс Foo, вы не можете предоставить байтовый массив для класса с другим именем, таким как подкласс.

...