- ベストアンサー
バイトコードを読み込み、処理を追加後ファイルに書き出す方法
こんにちは。 ファイルに書かれているバイトコードを読み込み、そのバイトコードへイベントハンドラー処理のコードを付け加えファイルへ出力したいと思います。 Javassistというものがあり、利用できたらと思いましたが、ASMを使う制約があります。 ClassLoaderではなく、ClassReader・ClassNode・acceptなどを使うのだと思いますが、どのように作成すればいいのか、取り掛かりの部分だけでも助言いただけると嬉しいです。 よろしくお願いします。
- みんなの回答 (1)
- 専門家の回答
質問者が選んだベストアンサー
「asmの導入部」だけ書きます。 たとえば、 ある「クラスファイル」を ただ読み込んで、何の変換も施さず、それを出力する処理は、 次のような流れになると思います。(※擬似コード) cr=new ClassReader(class_file_name)//読み込み用クラス cw=new ClassWriter();//書き出し用クラス cr.accept(cw)//クラスファイル解析&イベントディスパッチャ byte[] bytecode = cw.toByteArray();//結果のバイトコード --- クラスファイルを読み込んだあと、 その読み込まれたバイトコードを用いて「なんらかの処理( ※たとえば変換)」を施す場合は、 "イベントハンドラ(群を定義したクラス)"を「間にはさみ」ます。 cw=new ClassWriter(); ClassVisitor cv=new MyClassVisitor(cw);//イベントハンドラクラス cr.accept(cv) ・ ・ --- ようするに「XMLのSAX型処理」と同じということです。 SAXを知らないなら、まずそっちに親しみましょう。 --- 本家サイトのチュートリアル参照。 http://asm.objectweb.org/doc/tutorial.html
お礼
ご回答ありがとうございます。早速やってみましたが、ASMの部分に行く以前のjarファイルが、ClassReaderでうまく読み込めない事態に陥ってしまいました。下にコードを書きますので、おかしな点をご指摘いただけたらと思います。 public class Example extends ClassLoader { private static final class TestClassLoader extends ClassLoader{ public TestClassLoader(ClassLoader cl, String className){...} public Class loadClass(String name) throws ClassNotFoundException{ if(className.equals(name)){ try{ byte[] bytecode = transformClass(className); return super.defineClass(className, bytecode, 0, bytecode.length); }catch(IOException ex){ throw new ClassNotFoundException("Load error: " + ex.toString(), ex); } } return cl.loadClass(name); } private byte[] transformClass(String className) throws IOException{ String resource = className.replace('.', '/') + ".class"; InputStream is = getResourceAsStream(resource); byte[] b; ClassReader cr = new ClassReader(is);←ここでエラーがでます。 ClassWriter cw = new ClassWriter(true, true); NotifierClassVisitor ncv = new NotifierClassVisitor(cw); cr.accept(ncv, false); b = cw.toByteArray(); .... return b; } } public static void main(final String args[]) throws Exception { JarFile jarfile = new JarFile(args[0]); for(Enumeration en = jarfile.entries(); en.hasMoreElements();{ JarEntry entry = (JarEntry)en.nextElement(); if(entry.getName().endsWith(".class")){ String className = entry.getName().replaceAll("/", "\\.").replaceAll("\\.class", ""); ClassLoader loader = new TestClassLoader(entry.getClass().getClassLoader(), className); Class c = loader.loadClass(className); } } } 結果的に”Load error: java.io.IOException: Class not found”という形で終わってしまいます。