2012-06-18 31 views
8

chúng tôi đang sử dụng thư viện chứa các bean được chú thích bằng chú thích JAXB. không có gì trong cách chúng ta sử dụng các lớp này phụ thuộc vào JAXB. nói cách khác, chúng ta không cần JAXB và không phụ thuộc vào chú thích. Tuy nhiên,xóa bỏ chú thích sau khi biên dịch khỏi mã byte

tuy nhiên, vì chú thích tồn tại, chúng sẽ được tham chiếu bởi các lớp khác xử lý chú thích. điều này yêu cầu tôi gộp JAXB trong ứng dụng của chúng tôi, điều này không được phép, vì JAXB nằm trong gói javax.* (android không cho phép "thư viện cốt lõi" được đưa vào ứng dụng của bạn).

vì vậy, với điều này trong đầu, tôi đang tìm cách xóa chú thích khỏi mã byte được biên dịch. tôi biết có những tiện ích để thao tác mã byte, nhưng điều này khá mới đối với tôi. bất kỳ trợ giúp nào bắt đầu hướng tới mục tiêu này sẽ được đánh giá cao.

+0

Các lớp khác tham chiếu chúng là gì? Tại sao bạn có các lớp học đó được bao gồm trong ứng dụng Android của mình? –

+0

tôi không có quyền kiểm soát các lớp tham khảo các chú thích không may. chúng được tham chiếu từ một thư viện khác. –

+0

Tôi vẫn còn tò mò, thư viện tham khảo những lớp học này là gì? –

Trả lời

2

Tôi khuyên bạn nên sử dụng BCEL 6. Bạn cũng có thể sử dụng ASM, nhưng tôi nghe BCEL dễ sử dụng hơn. Dưới đây là phương pháp thử nghiệm nhanh để tạo trường cuối cùng:

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

Tất nhiên, bạn thực sự sẽ ghi lớp học của mình ra đĩa làm tệp rồi kết thúc nhưng điều này dễ dàng hơn để thử mọi thứ. Tôi không có BCEL 6 tiện dụng, vì vậy tôi không thể thay đổi ví dụ này để loại bỏ các chú thích, nhưng tôi tưởng tượng mã sẽ là một cái gì đó như:

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

Đối với bất kỳ ai cố gắng làm điều này - tôi cũng phải sửa đổi "ConstantPool" (nó chứa chú thích ngay cả sau khi loại bỏ nó khỏi các thuộc tính). Có thể tôi đã làm điều gì đó sai, nhưng nó hoạt động cho tôi bây giờ. – Mayjak

1

ProGuard cũng sẽ làm được điều này, ngoài việc Obfuscating mã của bạn .

+0

cảm ơn. có, nhưng nhận proguard để chạy chống lại một bộ rộng rãi và đa dạng của phụ thuộc là một dự án trong chính nó. tôi đã tìm kiếm một sửa chữa nhanh hơn (nếu nó tồn tại). –

+0

Tôi làm cách nào để thực hiện việc này với ProGuard? Tôi thấy tùy chọn '-keepattributes' có thể được sử dụng cho Chú thích nhưng không thấy nhiều về việc xóa. – theblang

1

Có thêm AntTask Purge Annotation References Ant Task, mà

Purge tham chiếu đến các chú thích ra khỏi bytecode java/classfiles (loại bỏ các thẻ @Anno từ các yếu tố chú thích). Bây giờ bạn có thể sử dụng các chú thích để kiểm tra các chòm sao trong bytecode sau khi biên dịch nhưng loại bỏ các annos đã sử dụng trước khi nhả các lọ.

0

Tôi đã sử dụng thư viện ByteBuddy để xóa chú thích. Rất tiếc, tôi không thể xóa chú thích với api cấp cao, vì vậy tôi đã sử dụng api ASM. Dưới đây là ví dụ, cách bạn có thể xóa chú thích @Deprecated khỏi trường của một lớp học:

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); 
    } 
} 
Các vấn đề liên quan