2016-07-05 20 views
1

ich eine Klasse mit dem folgenden Code rebase:VerifyError in Gson Klassen

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()); 

Wenn Laden der Klasse class com.google.gson.internal.ConstructorConstructor

es durch den Konstruktor geht, bis es schließlich zum Klasseninitialisierer von com.google.gson.internal.LinkedTreeMap bekommt.

Während dieser Initialisierung ich eine VerifyError erhalten:

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)

Als Referenz prüft der Abfangjäger im Grunde nur manuell für Paket-privaten Zugang (seit Paket private Methoden öffentlich gemacht wurden) und rufe dann nur superCall.call(). Ich glaube nicht, dass das Problem dort liegt.

Irgendwelche Ideen?

EDIT: Hier ist die PackagePrivateInterceptor: public class 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: Der folgende Code löst nicht das Problem:

//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()); 

Aber das folgende tut:

//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

Konnten Sie eine Wiederherstellung dieses Fehlers erzeugen? Normalerweise sollte dies nicht passieren und ich kann diesen Fehler nicht erzeugen. Byte Buddy verwendet ASM unter den Abdeckungen, die sich um den gesamten konstanten Pool kümmern, also nehme ich an, dass es ein Problem in der Bibliothek gibt. –

+0

Der Methodencode ist & ldquor; aload_0 aload_1 invokespecial [195] areurn ", der vernünftig aussieht, d. H. Nicht verworfen. Die Frage ist also, was mit dem Konstantenpool passiert ist, der einen Methodendeskriptor bei Index 195 enthalten sollte. Vielleicht könnte das Veröffentlichen des Ergebnisses von 'unloaded.getBytes()' (als hex dump) helfen ... – Holger

+0

@RafaelWinterHalter, ich habe versucht, eine saubere Erholung zu machen, aber das Problem tritt nicht auf. Offensichtlich ist es etwas, was ich tue, aber die Sache ist, dass ich keine Manipulation der Bytes oder irgendetwas mache. Ich werde untersuchen und versuchen zu sehen, was genau ich mache, die diesen Fehler auslöst. – erikh

Antwort

2

Dies ist in der Tat ein Fehler in Byte Buddy. Das Problem besteht darin, dass Sie eine Java 6-Klasse auf einer Java 8-VM neu ligasieren, wobei die Schnittstelle Comparable mehrere Standardmethoden implementiert. Sie weisen Byte Buddy an, diese Methoden zu überschreiben, und Sie weisen die Bibliothek außerdem an, diese Standardmethoden von einer überschriebenen Implementierung aufzurufen. Dies ist nicht legal für Java 6 Klassendateien, auch wenn die VM Java läuft 8.

Wenn ich Ihre Matcher cange:

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

der Fehler geht weg. Ich werde das in einer zukünftigen Version von Byte Buddy beheben.

Dieser Fehler wird derzeit weder von Byte Buddy noch von ASM abgefangen, was zu der merkwürdigen Fehlermeldung führt.

Aktualisieren: Der Fehler ist jetzt in Version 1.4.13 behoben.

+0

Funktioniert wie ein Charme! Vielen Dank. Ich nehme an, es war ein Fehler von mir, der einen Fehler in ASM/ByteBuddy ausgelöst hat. Es funktioniert, wenn isDefaultMethod hinzugefügt wird. Allerdings kann ich nicht auf die neueste Version von ByteBuddy aktualisieren, da dies ein neues Problem auslöst, aber ich werde eine andere Frage dazu stellen. – erikh

+0

In Bezug auf die andere Frage, egal, dass es anscheinend in 1.4.13 gelöst wurde. Es ging darum, den generischen Typ "E" nicht zu finden. – erikh