Видимость класса перехватчика в Byte Buddy

Byte Buddy, похоже, ценит общедоступные классы только как реализацию перехватчика, даже если я предоставляю фактический экземпляр; часто я ловлю себя на том, что хочу сделать что-то вроде этого:

import static MethodDelegation.to;

new ByteBuddy().subclass(Object.class).method(any()).intercept(to(new Object() {
  @RuntimeType
  public Object intercept(@Origin Method m, @AllArguments Object[] a) {
    return null;
  }
});

Что, однако, приводит к следующему исключению:

Exception in thread "main" java.lang.IllegalStateException: class net.bytebuddy.renamed.java.lang.Object$ByteBuddy$pUmdGhyP cannot access class us.levk.guice.vs.Scopes$1Builder$1

Есть ли причина для обеспечения видимости?

РЕДАКТИРОВАТЬ: у меня все еще есть проблемы с этим; Я получаю другое исключение, это мой код:

package us.levk.guice.vs;

import static net.bytebuddy.implementation.MethodDelegation.to;
import static net.bytebuddy.matcher.ElementMatchers.any;

import java.lang.reflect.Method;
import java.util.function.Function;
import java.util.function.Supplier;

import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;

public class Bar {

  Function<Supplier<?>, Class<?>> wrapper () {
    return s -> {
      return new ByteBuddy ().subclass (Object.class)
                             .name (Bar.class.getPackage ().getName () + ".Foo")
                             .method (any ())
                             .intercept (to (new Object () {
                               @RuntimeType
                               public Object intercept (@Origin Method method,
                                                        @AllArguments Object[] args) {
                                 System.out.println (method);
                                 return null;
                               }
                             }))
                             .make ()
                             .load (getClass ().getClassLoader (),
                                    ClassLoadingStrategy.Default.WRAPPER)
                             .getLoaded ();
    };
  }

  public static void main (String[] args) throws InstantiationException, IllegalAccessException {
    new Bar ().wrapper ().apply ( () -> new Integer (1)).newInstance ().toString ();
  }
}

И теперь исключение:

Exception in thread "main" java.lang.IllegalAccessError: tried to access class us.levk.guice.vs.Bar$1 from class us.levk.guice.vs.Foo

РЕДАКТИРОВАТЬ2:

Он отлично работает, если я изменю стратегию загрузки классов на INJECTION


person Lev Kuznetsov    schedule 13.01.2016    source источник


Ответы (1)


В этом случае Byte Buddy информирует вас об ограничении видимости, которое может вызвать IllegalAccessException во время выполнения.

Несмотря на то, что вы объявляете свой метод public, анонимный класс автоматически определяется javac как частный пакет. Поэтому метод не виден сгенерированному классу, так как net.bytebuddy.renamed.java.lang.Object не равно us.levk.guice.vs.Scopes.

Если вы сделали:

new ByteBuddy().subclass(Object.class).name("us.levk.guice.vs.Foo")
               .method(any()).intercept(to(new Object() {
  @RuntimeType
  public Object intercept(@Origin Method m, @AllArguments Object[] a) {
    return null;
  }
}));

все будет работать. В качестве альтернативы вы можете определить, например, общедоступный интерфейс, такой как:

public interface Foo {
  @RuntimeType
  Object intercept(@Origin Method m, @AllArguments Object[] a);
}

new ByteBuddy().subclass(Object.class).name("us.levk.guice.vs.Foo")
               .method(any()).intercept(to(new Foo() {
  @RuntimeType
  public Object intercept(@Origin Method m, @AllArguments Object[] a) {
    return null;
  }
}, Foo.class));
person Rafael Winterhalter    schedule 13.01.2016