2012-06-18 5 views
8

우리는 JAXB 주석으로 주석 처리 된 bean을 포함하는 라이브러리를 사용하고 있습니다. 우리가 이러한 클래스를 사용하는 방식은 JAXB에 따라 다릅니다. 즉, 우리는 JAXB가 필요없고 주석에 의존하지 않습니다.post-compilation 바이트 코드에서 주석을 제거합니다.

그러나 주석은 존재하기 때문에 주석을 처리하는 다른 클래스에 의해 참조됩니다. JAXB가 javax.* 패키지에 있으므로 (JAXB가 응용 프로그램에 "핵심 라이브러리"를 포함 할 수 없음) JAXB가 응용 프로그램에 번들로 제공되어야합니다.

그래서이 점을 염두에두고 컴파일 된 바이트 코드에서 주석을 제거 할 방법을 찾고 있습니다. 바이트 코드를 조작하는 유틸리티가 있다는 것을 알고 있지만 이것은 나에게있어서 아주 새로운 것이다. 이 목적을 향해 시작하는 데 도움이 될 것입니다.

+0

다른 클래스는 어떤 클래스를 참조합니까? 왜 당신은 당신의 안드로이드 애플 리케이션에 포함 된 클래스가 있습니까? –

+0

불행히도 주석을 참조하는 클래스를 제어 할 권한이 없습니다. 다른 라이브러리에서 참조됩니다. –

+0

아직도 궁금한 점이 있습니까?이 수업을 참조하는 도서관은 무엇입니까? –

답변

2

BCEL 6을 권장합니다. ASM을 사용할 수도 있지만 BCEL은 사용하기가 더 쉽다고 들었습니다. 다음은 최종 필드를 만들기위한 간단한 테스트 방법입니다 : 물론

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

누구나이 작업을 시도해 보려는 경우 - "ConstantPool"(속성에서 속성을 제거한 후에도 주석이 포함되어 있음)을 수정해야했습니다. 내가 뭔가 잘못했을 수도 있지만 지금은 저에게 효과적입니다. – Mayjak

1

ProGuard에서 또한뿐만 아니라,이 작업을 수행 할 것 .

+0

감사합니다. 예, 그렇지만 프로 가드를 다양하고 다양한 의존성에 맞춰 실행하는 것은 하나의 프로젝트입니다. 나는 더 빠른 수정 (존재한다면)을 찾고 있었다. –

+0

ProGuard로 어떻게 할 수 있습니까? Annotations에 사용할 수있는'-keepattributes' 옵션이 있지만 제거에 대해서는별로 보지 못합니다. – theblang

1

은 자바 바이트 코드에 주석 중

퍼지 참조/클래스 파일이 (주석 요소로부터 @Anno 태그 제거) 추가 AntTask Purge Annotation References Ant Task,있다. 이제 주석을 사용하여 컴파일 후 바이트 코드의 별자리를 확인할 수 있지만 은 jars를 해제하기 전에 사용 된 주석을 제거합니다.

0

나는 주석을 제거하기 위해 ByteBuddy 라이브러리를 사용했습니다. 불행히도 고급 API를 사용하여 주석을 제거 할 수 없어 ASM API를 사용했습니다. 다음은 @Deprecated 주석을 클래스 필드에서 제거하는 방법의 예입니다.

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