ASM: Assemblernya Java


Just kidding… ASM yang sedang aku pelajarin bukanlah bahasa mesin Java, tetapi suatu library untuk mengotak-atik class Java yang sudah tercompile. Konon nama library tersebut diambil dari keyword __asm__ di C, yang kepanjangannya mungkin adalah assembler.

Seandainya aku memiliki sebuah class dari source berikut:

package latihan;

public class Music {

  private String musicID;
  private String title;

  public String getMusicID() {
    return musicID;
  }
  public void setMusicID(String musicId) {
    musicID = musicId;
  }
  public String getTitle() {
    return title;
  }
  public void setTitle(String title) {
    this.title = title;
  }

}

Class tersebut aku simpan dengan nama di folder c:\ dengan nama music.class. Dengan bantuan ASM, aku akan membuat program untuk membaca file music.class dan menampilkan setiap variabel dan method milik class tersebut:

public class Main {

  public Main() {
    try {
      BufferedInputStream bis = new BufferedInputStream(new FileInputStream("c:\\Music.class"));
      ClassReader classReader = new ClassReader(bis);
      classReader.accept(new ClassEventHandler(), 0);
      bis.close();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  public static void main(String[] args) {
    new Main();
  }

  protected class ClassEventHandler implements ClassVisitor {

    @Override
    public void visit(int version, int access, String name,
        String signature, String superName, String[] interfaces) {

      System.out.println("Classname: " + name);
      System.out.println("Superclass Name: " + superName);
      System.out.println("Implements Interface: " + interfaces.toString() + "\n");

    }

    @Override
    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
      return null;
    }

    @Override
    public void visitAttribute(Attribute attr) {
    }

    @Override
    public void visitEnd() {
      System.out.println("\nVisit End");
    }

    @Override
    public FieldVisitor visitField(int access, String name, String desc,
        String signature, Object value) {

      System.out.println("Field Descriptor: " + desc);
      System.out.println("Field Name: " + name);
      System.out.println("\n");
      return null;

    }

    @Override
    public void visitInnerClass(String name, String outerName,
        String innerName, int access) {
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
        String signature, String[] exceptions) {

      System.out.println("Method Descriptor: " + desc);
      System.out.println("Method Name: " + name);
      System.out.println("\n");
      return null;
    }

    @Override
    public void visitOuterClass(String owner, String name, String desc) {
    }

    @Override
    public void visitSource(String source, String debug) {
    }

  }

}

Hasil dari program di atas adalah:

Classname: latihan/Music
Superclass Name: java/lang/Object
Implements Interface: [Ljava.lang.String;@190d11

Field Descriptor: Ljava/lang/String;
Field Name: musicID

Field Descriptor: Ljava/lang/String;
Field Name: title

Method Descriptor: ()V
Method Name: <init>

Method Descriptor: ()Ljava/lang/String;
Method Name: getMusicID

Method Descriptor: (Ljava/lang/String;)V
Method Name: setMusicID

Method Descriptor: ()Ljava/lang/String;
Method Name: getTitle

Method Descriptor: (Ljava/lang/String;)V
Method Name: setTitle

Visit End

Output di atas memakai penamaan internal setelah class di-compile. Wajar saja, karena yang dibaca bukanlah source code program Java, melainkan class Java yang sudah ter-compile. Sebagai contoh, descriptor Ljava/lang/String menunjukkan bahwa itu adalah tipe data java.lang.String. Nilai lain yang mungkin seperti Z untuk boolean, C untuk char, B untuk byte, dan sebagainya. Descriptor ()V pada method menunjukkan bahwa method tersebut tidak menerima argumen dan tidak mengembalikan nilai (void). Descriptor (Ljava/lang/String;)V menunjukkan bahwa method tersebut tidak mengembalikan nilai (void), dan menerima parameter berupa sebuah object java.lang.String.

ASM tidak hanya bisa membaca class, tapi juga bisa membuat class ke dalam bentuk byte array. Byte array ini nantinya dapat ditulis ke dalam file, atau langsung di-load oleh JVM untuk dipakai. Sebagai contoh, aku akan membuat program Java yang membuat class Music di memory (tanpa membuat source code Music.java):

package latihan;

import java.lang.reflect.Field;
import org.objectweb.asm.ClassWriter;
import static org.objectweb.asm.Opcodes.*;

public class Main {

  public Main() {

    MusicClassLoader cl = new MusicClassLoader();
    try {
      Class<?> c = cl.findClass("latihan.Music");
      System.out.println("Class name = " + c.getName());
      for (Field f : c.getFields()) {
        System.out.println("Field name: " + f.getName() + "; Field type: " + f.getType());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }

  }

  public static void main(String args[]) {
    new Main();
  }

  protected class MusicClassLoader extends ClassLoader {

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
      if (name.equals("latihan.Music")) {
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_6, ACC_PUBLIC, "latihan/Music", null, "java/lang/Object", null);
        cw.visitField(ACC_PUBLIC, "musicID", "Ljava/lang/String;", null, null);
        cw.visitField(ACC_PUBLIC, "title", "Ljava/lang/String;", null, null);
        cw.visitEnd();
        byte[] b = cw.toByteArray();
        return defineClass("latihan.Music", b, 0, b.length);
      }
      return findClass(name);
    }
  }
}

Pada contoh di atas, class latihan.Music yang aku buat on-the-fly terlihat tidak begitu berguna karena ia bukan tidak memiliki ‘kontrak’ yang jelas (misalnya tidak melakukan implementasi interface tertentu). Pada tulisan berikutnya, aku akan mencoba mempelajari fungsi ASM yang lain, yaitu melakukan transformasi class.

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: