2012-06-18 11 views
8

Wir verwenden eine Bibliothek, die Beans enthält, die mit JAXB-Annotationen versehen sind. nichts in der Art, wie wir diese Klassen verwenden, hängt von JAXB ab. Mit anderen Worten, wir brauchen JAXB nicht und sind nicht von den Anmerkungen abhängig.Nach der Kompilierung Entfernen von Anmerkungen aus dem Bytecode

Da die Anmerkungen jedoch vorhanden sind, werden sie von anderen Klassen referenziert, die Annotationen verarbeiten. Dies erfordert, dass ich JAXB in unserer Anwendung bündle, was nicht erlaubt ist, weil JAXB im Paket javax.* ist (Android erlaubt nicht, dass "Kernbibliotheken" in Ihrer Anwendung enthalten sind).

Also, in diesem Sinne suche ich nach einer Möglichkeit, die Anmerkungen aus dem kompilierten Byte-Code zu entfernen. Ich weiß, es gibt Dienstprogramme für die Manipulation von Byte-Code, aber das ist ziemlich neu für mich. jede Hilfe, die zu diesem Zweck begonnen wird, würde geschätzt werden.

+0

Welche anderen Klassen verweisen sie? Warum haben Sie diese Klassen in Ihrer Android-App enthalten? –

+0

Ich habe leider keine Kontrolle über die Klassen die Referenz die Annotationen. Sie werden von einer anderen Bibliothek referenziert. –

+0

Ich bin immer noch neugierig, was ist die Bibliothek, die diese Klassen verweist? –

Antwort

2

Ich empfehle BCEL 6. Sie können auch ASM verwenden, aber ich höre, dass BCEL einfacher zu verwenden ist. Hier ist eine schnelle Testverfahren zur Herstellung einer Feld Finale:

public static void main(String[] args) throws Exception { 
    System.out.println(F.class.getField("a").getModifiers()); 
    JavaClass aClass = Repository.lookupClass(F.class); 
    ClassGen aGen = new ClassGen(aClass); 
    for (Field field : aGen.getFields()) { 
     if (field.getName().equals("a")) { 
      int mods = field.getModifiers(); 
      field.setModifiers(mods | Modifier.FINAL); 
     } 
    } 
    final byte[] classBytes = aGen.getJavaClass().getBytes(); 
    ClassLoader cl = new ClassLoader(null) { 
     @Override 
     protected synchronized Class<?> findClass(String name) throws ClassNotFoundException { 
      return defineClass("F", classBytes, 0, classBytes.length); 
     } 
    }; 
    Class<?> fWithoutDeprecated = cl.loadClass("F"); 
    System.out.println(fWithoutDeprecated.getField("a").getModifiers()); 
} 

Natürlich würden Sie tatsächlich schreiben Sie Ihre Klassen auf der Festplatte als Dateien und dann jar sie, aber das ist leichter für Dinge auszuprobieren. Ich habe nicht BCEL 6 handlich, deshalb kann ich dieses Beispiel nicht ändern, um Anmerkungen zu entfernen, aber ich glaube, der Code so etwas wie sein würde:

public static void main(String[] args) throws Exception { 
    ... 
    ClassGen aGen = new ClassGen(aClass); 
    aGen.setAttributes(cleanupAttributes(aGen.getAttributes())); 
    aGen.getFields(); 
    for (Field field : aGen.getFields()) { 
     field.setAttributes(cleanupAttributes(field.getAttributes())); 
    } 
    for (Method method : aGen.getMethods()) { 
     method.setAttributes(cleanupAttributes(method.getAttributes())); 
    } 
    ... 
} 

private Attribute[] cleanupAttributes(Attribute[] attributes) { 
    for (Attribute attribute : attributes) { 
     if (attribute instanceof Annotations) { 
      Annotations annotations = (Annotations) attribute; 
      if (annotations.isRuntimeVisible()) { 
       AnnotationEntry[] entries = annotations.getAnnotationEntries(); 
       List<AnnotationEntry> newEntries = new ArrayList<AnnotationEntry>(); 
       for (AnnotationEntry entry : entries) { 
        if (!entry.getAnnotationType().startsWith("javax")) { 
         newEntries.add(entry); 
        } 
       } 
       annotations.setAnnotationTable(newEntries); 
      } 
     } 
    } 
    return attributes; 
} 
+0

Für jeden, der dies versuchte - ich musste auch das "ConstantPool" ändern (es enthielt die Annotation auch nach dem Entfernen von den Attributen). Es könnte sein, dass ich etwas falsch gemacht habe, aber es funktioniert jetzt für mich. – Mayjak

1

ProGuard wird dies auch tun, aber auch Ihren Code zu verschleiern .

+0

danke. Ja, aber es ist ein Projekt für sich, sich gegen eine breite und vielfältige Reihe von Abhängigkeiten zu behaupten. Ich war auf der Suche nach einer schnelleren Lösung (wenn es existiert). –

+0

Wie kann ich das mit ProGuard machen? Ich sehe eine Option "-keepattributes", die für Anmerkungen verwendet werden kann, aber nicht viel über das Entfernen sieht. – theblang

1

Es gibt eine zusätzliche AntTask Purge Annotation References Ant Task, die

Purge Verweise auf Annotationen aus dem Java-Bytecode/ Klassendateien (die @Anno Tag aus kommentierten Elemente entfernen). Jetzt können Sie Annotationen verwenden, um Konstellationen in Bytecode nach der Kompilierung zu überprüfen, aber entfernen Sie die verwendeten Annos vor der Freigabe der Gläser.

0

Ich habe ByteBuddy Bibliothek verwendet, um Anmerkungen zu entfernen. Leider konnte ich Annotationen mit High-Level-API nicht entfernen, daher verwendete ich ASM api. Hier ist ein Beispiel, wie Sie @Deprecated Annotation aus dem Feld einer Klasse entfernen können:

import net.bytebuddy.ByteBuddy; 
import net.bytebuddy.asm.AsmVisitorWrapper; 
import net.bytebuddy.description.field.FieldDescription; 
import net.bytebuddy.description.type.TypeDescription; 
import net.bytebuddy.jar.asm.AnnotationVisitor; 
import net.bytebuddy.jar.asm.FieldVisitor; 
import net.bytebuddy.jar.asm.Opcodes; 
import net.bytebuddy.jar.asm.Type; 
import net.bytebuddy.matcher.ElementMatchers; 

import java.lang.annotation.Annotation; 
import java.util.Arrays; 

public class Test { 

    public static class Foo { 
     @Deprecated 
     public Integer bar; 
    } 

    public static void main(String[] args) throws Exception { 
     System.out.println("Annotations before processing " + getAnnotationsString(Foo.class)); 
     Class<? extends Foo> modifiedClass = new ByteBuddy() 
       .redefine(Foo.class) 
       .visit(new AsmVisitorWrapper.ForDeclaredFields() 
         .field(ElementMatchers.isAnnotatedWith(Deprecated.class), 
           new AsmVisitorWrapper.ForDeclaredFields.FieldVisitorWrapper() { 
            @Override 
            public FieldVisitor wrap(TypeDescription instrumentedType, 
                  FieldDescription.InDefinedShape fieldDescription, 
                  FieldVisitor fieldVisitor) { 
             return new FieldVisitor(Opcodes.ASM5, fieldVisitor) { 
              @Override 
              public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 
               if (Type.getDescriptor(Deprecated.class).equals(desc)) { 
                return null; 
               } 
               return super.visitAnnotation(desc, visible); 
              } 
             }; 
            } 
           })) 
       // can't use the same name, because Test$Foo is already loaded 
       .name("Test$Foo1") 
       .make() 
       .load(Test.class.getClassLoader()) 
       .getLoaded(); 
     System.out.println("Annotations after processing " + getAnnotationsString(modifiedClass)); 
    } 

    private static String getAnnotationsString(Class<? extends Foo> clazz) throws NoSuchFieldException { 
     Annotation[] annotations = clazz.getDeclaredField("bar").getDeclaredAnnotations(); 
     return Arrays.toString(annotations); 
    } 
} 
Verwandte Themen