2016-07-05 2 views
1

I класс пересчитать динамические со следующим кодом:VerifyError в Gson классы

DynamicType.Unloaded unloaded = new ByteBuddy().with(TypeValidation.DISABLED).rebase(typeDescription, 
       ClassFileLocator.Simple.of(className, classBytes, 
         ClassFileLocator.ForClassLoader.of((ClassLoader) classLoader))).method(
       ElementMatchers.isPackagePrivate().and(ElementMatchers.not(ElementMatchers.isAbstract()))).intercept(
       MethodDelegation.to(PackagePrivateInterceptor.class)).transform(
       MethodTransformer.Simple.withModifiers(Visibility.PUBLIC)).make(); 
     return new ClassPair(unloaded.load((ClassLoader) classLoader, 
       ClassLoadingStrategy.Default.INJECTION.withProtectionDomain(
         classLoader.getClass().getProtectionDomain())).getLoaded(), unloaded.getBytes()); 

При загрузке класса class com.google.gson.internal.ConstructorConstructor

он проходит через конструктор, пока, наконец, не добирается до класса инициализаторе com.google.gson.internal.LinkedTreeMap.

Во время этой инициализации, я получаю VerifyError:

1:24:20.227 [main] ERROR [io.hakansson.dynamicjar.core.main.Bootstrap] - java.lang.RuntimeException: java.lang.VerifyError: Illegal type at constant pool entry 195 in class com.google.gson.internal.LinkedTreeMap$1 
Exception Details: 
    Location: 
    com/google/gson/internal/LinkedTreeMap$1.thenComparing$accessor$vT023QbO(Ljava/util/function/Function;)Ljava/util/Comparator; @2: invokespecial 
    Reason: 
    Constant pool index 195 is invalid 
    Bytecode: 
    0x0000000: 2a2b b700 c3b0       

    at io.hakansson.dynamicjar.core.api.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:52) 
    at io.hakansson.dynamicjar.core.main.Bootstrap.main(Bootstrap.java:42) 
Caused by: java.lang.VerifyError: Illegal type at constant pool entry 195 in class com.google.gson.internal.LinkedTreeMap$1 
Exception Details: 
    Location: 
    com/google/gson/internal/LinkedTreeMap$1.thenComparing$accessor$vT023QbO(Ljava/util/function/Function;)Ljava/util/Comparator; @2: invokespecial 
    Reason: 
    Constant pool index 195 is invalid 
    Bytecode: 
    0x0000000: 2a2b b700 c3b0       

    at com.google.gson.internal.LinkedTreeMap.classInitializer$oNOjADym(LinkedTreeMap.java:40) 
    at com.google.gson.internal.LinkedTreeMap.(LinkedTreeMap.java) 
    at com.google.gson.internal.ConstructorConstructor$13.construct$original$gt92dwVY(ConstructorConstructor.java:207) 
    at com.google.gson.internal.ConstructorConstructor$13.construct$original$gt92dwVY$accessor$lof1omy8(ConstructorConstructor.java) 
    at com.google.gson.internal.ConstructorConstructor$13$auxiliary$oB71rVyd.call(Unknown Source) 
    at io.hakansson.dynamicjar.nestedjarclassloader.PackagePrivateInterceptor.intercept(PackagePrivateInterceptor.java:29) 
    at com.google.gson.internal.ConstructorConstructor$13.construct(ConstructorConstructor.java) 
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:167) 
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read$original$ZTjOtCtb(ReflectiveTypeAdapterFactory.java:116) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read$original$ZTjOtCtb$accessor$WgRdwpwl(ReflectiveTypeAdapterFactory.java) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1$auxiliary$41HBhnNS.call(Unknown Source) 
    at io.hakansson.dynamicjar.nestedjarclassloader.PackagePrivateInterceptor.intercept(PackagePrivateInterceptor.java:29) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read$original$bOjIYDn5(TypeAdapterRuntimeTypeWrapper.java:40) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read$original$bOjIYDn5$accessor$hMWEZRZS(TypeAdapterRuntimeTypeWrapper.java) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper$auxiliary$U1tyihKy.call(Unknown Source) 
    at io.hakansson.dynamicjar.nestedjarclassloader.PackagePrivateInterceptor.intercept(PackagePrivateInterceptor.java:29) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java) 
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82) 
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read$original$ZTjOtCtb(ReflectiveTypeAdapterFactory.java:116) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read$original$ZTjOtCtb$accessor$WgRdwpwl(ReflectiveTypeAdapterFactory.java) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1$auxiliary$41HBhnNS.call(Unknown Source) 
    at io.hakansson.dynamicjar.nestedjarclassloader.PackagePrivateInterceptor.intercept(PackagePrivateInterceptor.java:29) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java) 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216) 
    at com.google.gson.Gson.fromJson(Gson.java:879) 
    at com.google.gson.Gson.fromJson(Gson.java:817)

Для справки, перехватчик в основном только вручную проверяет пакет-частного доступа (поскольку пакет частные методы были опубликованы), а затем просто вызывает superCall.call(). Я не верю, что там лежит проблема.

Любые идеи?

EDIT: Вот PackagePrivateInterceptor: общественный класс PackagePrivateInterceptor {

@RuntimeType 
@BindingPriority(1) 
public static Object intercept(@SuperCall Callable<?> superCall, @Origin Class targetClass, @Origin String method) throws 
     Exception 
{ 

    Class callingClass = new InternalSecurityManager().getCallingClass(); 
    String targetPackage = targetClass.getPackage().getName(); 
    if (!callingClass.getPackage().getName().equals(targetPackage)) { 
     throw new IllegalAccessError(callingClass + " cannot access method " + method + " of Class " + targetClass); 
    } 

    //Default: 
    return superCall.call(); 
} 

private static class InternalSecurityManager extends SecurityManager { 
    Class getCallingClass() { 
     Class[] classContext = getClassContext(); 
     for (Class current : classContext) { 
      if (current.getName().startsWith("java.") || 
        current.getName().equals(PackagePrivateInterceptor.class.getName()) || 
        current.getName().equals(InternalSecurityManager.class.getName())) 
      { 
       continue; 
      } 
      return current; 
     } 
     throw new IllegalStateException("Failed to find calling Class"); 
    } 
} 

EDIT2: Следующий код не вызывает вопрос:

//Only package-private methods should be proxied. 
      DynamicType.Unloaded unloaded = new ByteBuddy().with(TypeValidation.DISABLED).rebase(typeDescription, 
        ClassFileLocator.Simple.of(className, classBytes, 
          ClassFileLocator.ForClassLoader.of((ClassLoader) classLoader))).method(
        ElementMatchers.isPackagePrivate().and(ElementMatchers.not(ElementMatchers.isAbstract()))).intercept(
        MethodDelegation.to(PackagePrivateInterceptor.class)).transform(
        MethodTransformer.Simple.withModifiers(Visibility.PUBLIC)).make(); 
      DynamicType.Loaded loaded = unloaded.load((ClassLoader) classLoader, 
        ClassLoadingStrategy.Default.INJECTION.withProtectionDomain(
          classLoader.getClass().getProtectionDomain())); 
      if (className.equals("com.google.gson.internal.LinkedTreeMap")) 
       System.out.println(DatatypeConverter.printHexBinary(loaded.getBytes())); 
      return new ClassPair(loaded.getLoaded(), unloaded.getBytes()); 

Но на следующий же:

//All non-private methods should be proxied 
      //TODO: Actually, the class itself should be made visible and still only package-private methods should be proxied. 
      DynamicType.Unloaded unloaded = new ByteBuddy().with(TypeValidation.DISABLED).rebase(typeDescription, 
        ClassFileLocator.Simple.of(className, classBytes, 
          ClassFileLocator.ForClassLoader.of((ClassLoader) classLoader))).method(
        ElementMatchers.not(ElementMatchers.isPrivate()).and(
          ElementMatchers.not(ElementMatchers.isAbstract()))).intercept(
        MethodDelegation.to(PackagePrivateInterceptor.class)).transform(
        MethodTransformer.Simple.withModifiers(Visibility.PUBLIC)).make(); 
      return new ClassPair(unloaded.load((ClassLoader) classLoader, 
        ClassLoadingStrategy.Default.INJECTION.withProtectionDomain(
          classLoader.getClass().getProtectionDomain())).getLoaded(), unloaded.getBytes()); 
+0

Не могли бы вы создать воссоздание этой ошибки? Обычно этого не должно происходить, и я не могу создать эту ошибку. Byte Buddy использует ASM под обложками, которые заботятся обо всем постоянном пуле, поэтому я предполагаю, что в библиотеке есть проблема. –

+0

Код метода: aload_0 aload_1 invokespecial [195] areturn', который выглядит разумным, т. Е. Не разбит. Итак, вопрос в том, что произошло с постоянным пулом, который должен содержать дескриптор метода в индексе '195'. Может быть, публикация результата 'unloaded.getBytes()' (как hex dump) может помочь ... – Holger

+0

@RafaelWinterHalter, я пытался сделать чистый отдых, но проблема не возникает. Очевидно, это то, что я делаю, но дело в том, что я не делаю никаких манипуляций с байтами или чем-то еще. Я буду исследовать и попытаться выяснить, что именно я делаю, что вызывает эту ошибку. – erikh

ответ

2

Это действительно ошибка в Byte Buddy. Проблема в том, что вы переустанавливаете класс Java 6 на виртуальной машине Java 8, где интерфейс Comparable реализует несколько методов по умолчанию. Вы инструктируете Byte Buddy переопределить эти методы, и вы также поручаете библиотеке вызывать эти методы по умолчанию из переопределенной реализации. Это не является законным для файлов Java 6 класса, даже если виртуальная машина работает под управлением Java 8.

Если я Канг вашего Искателя к:

not(isPrivate().or(isAbstract()).or(isDefaultMethod())) 

ошибка уходит. Я исправлю это в будущей версии Byte Buddy.

В настоящее время эта ошибка не улавливается ни Byte Buddy, ни ASM, которая вызывает странное сообщение об ошибке.

Обновление: Ошибка разрешена в версии 1.4.13.

+0

Работает как очарование! Спасибо. Поэтому я полагаю, что это была ошибка, вызвав ошибку в ASM/ByteBuddy. Он работает при добавлении isDefaultMethod. Однако я не могу обновить до последней версии ByteBuddy, поскольку это вызывает новую проблему, но я отправлю еще один вопрос об этом. – erikh

+0

Что касается другой проблемы, неважно, она была, по-видимому, решена в 1.4.13. Это было чем-то вроде того, что не нашел общий тип «E». – erikh

Смежные вопросы