2012-06-18 22 views
8

से एनोटेशन के बाद संकलन हटाने के बाद हम एक लाइब्रेरी का उपयोग कर रहे हैं जिसमें बीएक्स शामिल हैं जो जेएक्सबी एनोटेशन के साथ एनोटेटेड हैं। इन वर्गों का उपयोग करने के तरीके में कुछ भी नहीं JAXB पर निर्भर करता है। दूसरे शब्दों में, हमें JAXB की आवश्यकता नहीं है और एनोटेशन पर निर्भर नहीं है।बाइट कोड

हालांकि, एनोटेशन मौजूद हैं, इसलिए वे एनोटेशन को संसाधित करने वाले अन्य वर्गों द्वारा संदर्भित किए जाते हैं। इसके लिए मुझे हमारे आवेदन में जेएक्सबी को बंडल करने की आवश्यकता है, जिसकी अनुमति नहीं है, क्योंकि जेएक्सबी javax.* पैकेज में है (एंड्रॉइड आपके कोर में "कोर लाइब्रेरीज़" को शामिल करने की अनुमति नहीं देता है)।

इसलिए, इस बात को ध्यान में रखते हुए, मैं संकलित बाइट कोड से एनोटेशन को हटाने का एक तरीका ढूंढ रहा हूं। मुझे पता है कि बाइट कोड में हेरफेर करने के लिए उपयोगिताएं हैं, लेकिन यह मेरे लिए काफी नया है। इस अंत की ओर शुरू करने में कोई मदद की सराहना की जाएगी।

+0

अन्य कक्षाएं उन्हें संदर्भित करती हैं? आपके एंड्रॉइड ऐप में उन कक्षाओं को क्यों शामिल किया गया है? –

+0

दुर्भाग्य से एनोटेशन के संदर्भ में कक्षाओं पर मेरा नियंत्रण नहीं है। उन्हें एक और पुस्तकालय से संदर्भित किया जाता है। –

+0

मैं अभी भी उत्सुक हूं, पुस्तकालय क्या है जो इन वर्गों का संदर्भ देता है? –

उत्तर

2

मैं बीसीईएल 6 की सिफारिश करता हूं। आप एएसएम का भी उपयोग कर सकते हैं, लेकिन मुझे लगता है कि बीसीईएल का उपयोग करना आसान है। यहाँ एक क्षेत्र अंतिम बनाने के लिए एक त्वरित परीक्षण विधि है:

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()); 
} 
बेशक

, आप वास्तव में फ़ाइलों के रूप में डिस्क के लिए बाहर अपनी कक्षाओं बारे में और उसके बाद उन्हें जार होगा, लेकिन यह बातें आज़माने के लिए आसान है। मैं BCEL 6 आसान नहीं है, इसलिए मैं एनोटेशन बाहर निकालना इस उदाहरण संशोधित नहीं कर सकते, लेकिन मुझे लगता है कोड होगा कुछ की तरह: अपने कोड करना मुश्किल होता करने के लिए

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

किसी को भी ऐसा करने का प्रयास करने के लिए - मुझे "कॉन्स्टेंटपूल" को भी संशोधित करना पड़ा (इसमें गुणों से इसे हटाने के बाद भी एनोटेशन शामिल था)। हो सकता है कि मैंने कुछ गलत किया हो, लेकिन यह अब मेरे लिए काम करता है। – Mayjak

1

ProGuard भी इसके अलावा में यह कर देगा, ।

+0

धन्यवाद। हां, लेकिन निर्भरता के एक विस्तृत और विविध सेट के खिलाफ चलाने के लिए प्रोगार्ड प्राप्त करना एक परियोजना है। मैं एक तेज फिक्स की तलाश में था (अगर यह अस्तित्व में था)। –

+0

मैं ProGuard के साथ यह कैसे कर सकता हूं? मुझे एक '-keepattributes' विकल्प दिखाई देता है जिसका उपयोग एनोटेशन के लिए किया जा सकता है, लेकिन हटाने के बारे में बहुत कुछ नहीं देख रहा है। – theblang

1

एक अतिरिक्त AntTask Purge Annotation References Ant Task, जो

शुद्ध एनोटेशन के लिए संदर्भ जावा बाईटकोड से बाहर/classfiles (एनोटेट तत्वों से @Anno टैग हटाने) नहीं है। अब संकलन के बाद बाइटकोड में नक्षत्रों की जांच के लिए एनोटेशन का उपयोग कर सकते हैं लेकिन जार जारी करने से पहले उपयोग किए गए एनोस को हटा दें।

0

मैंने एनोटेशन को हटाने के लिए ByteBuddy लाइब्रेरी का उपयोग किया है। दुर्भाग्य से मैं उच्च स्तरीय एपीआई के साथ एनोटेशन को हटाने में असमर्थ था, इसलिए मैंने एएसएम एपीआई का इस्तेमाल किया। यहां उदाहरण दिया गया है, आप कक्षा के क्षेत्र से @ डेपरेटेड एनोटेशन को कैसे हटा सकते हैं:

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