Examples

ClassNamePrinter

処理器に与えられたクラスの名前を出力するだけの Processor を作成します.

まず,Generator のページの Generate BytecodeProcessor project を参照し,nameprinter を作成してください.

作成されるデフォルトの Java ソースファイルは以下のようなものです.

// this class is generated by Rocinante 1.0
package jp.cafebabe.donquixote.plugins.nameprinter;

import java.io.PrintWriter;
import java.net.URL;

import org.apache.bcel.classfile.JavaClass;

import jp.cafebabe.donquixote.rocinante.Summary;
import jp.cafebabe.donquixote.rocinante.processors.AbstractBytecodeProcessor;
import jp.cafebabe.donquixote.rocinante.summary.FormattedSummary;

public class ClassNamePrinter extends AbstractBytecodeProcessor{
    private FormattedSummary summary;
    private PrintWriter out;
    private int index = 0;

    @Override
    public void initialize(){
        summary = new FormattedSummary(getName());
        out = summary.getWriter();
    }

    @Override
    public void perform(JavaClass target, URL location){
        index++;
        out.println(index + ": " + target.getClassName());
    }

    @Override
    protected Summary summarize(){
        return summary;
    }
}

これは perform が実行されるたびに,クラス名を Summary に書き出し,最 後に処理対象となったクラス名が Summary の出力によってユーザに提示され るという処理器です.

また,src/main/resources/META-INF/plugins.xml も必要に応じて修正して ください.author-information や properties,そして,description が主な 修正箇所となると思います.

<?xml version="1.0" encoding="euc-jp"?>

<!--
  This configuration file is generated by Rocinante 1.0
-->
<donquixote-plugins>
  <author-information>
    <organizations>
      <organization>
        <name>cafebabe.jp</name>
        <url>http://www.cafebabe.jp/</url>
      </organization>
    </organizations>
    <authors>
      <author>
        <name>Haruaki TAMADA</name>
        <email>tamada[ at ]cafebabe.jp</email>
        <organization-name>cafebabe.jp</organization-name>
      </author>
    </authors>
  </author-information>

  <plugins>
    <plugin>
      <name>nameprinter</name>
      <description>Sample BytecodeProcessor</description>
      <processor>jp.cafebabe.donquixote.plugins.nameprinter.ClassNamePrinter</processor>
<!--
      <properties>
        <property>
          <name>property.name</name>
          <description>Description of this property</description>
          <value>Default value of this property</value>
        </property>
      </properties>
-->
    </plugin>
  </plugins>
</donquixote-plugins>

NopDeleteProcessor

続いて,FilterBytecodeProcessor の例を示します.

先ほどの例と同じく,Generator のページの Generate FilterBytecodeProcessor project を参照し,deletenop を作成してくださ い.

NOP を削除するために,BCUL を用 います.BCUL のサンプルに NopDeleteInstructionUpdateHandler がありますので,これを使うことにします.依存ライブラリが増えるため, pom.xml に以下の記述を追加します.

      :
    <dependency>
      <groupId>jp.cafebabe.commons</groupId>
      <artifactId>bcul</artifactId>
      <version>1.0</version>
      <scope>compile</scope>
    </dependency>
      :

BCUL サンプルにあ るNopDeleteInstructionUpdateHandler を以下のように少し修正します.いく つの NOP を削除したのかを得るためです.

package jp.cafebabe.donquixote.plugins.deletenop;

import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.NOP;

import jp.cafebabe.commons.bcul.updater.AbstractInstructionUpdateHandler;
import jp.cafebabe.commons.bcul.updater.UpdateData;
import jp.cafebabe.commons.bcul.updater.UpdateType;

class NopDeleteInstructionUpdateHandler extends AbstractInstructionUpdateHandler{
    private int count = 0; // add new field

    /**
     * add new method.
     */
    public void reset(){
        count = 0;
    }

    /**
     * add new method
     */
    public int getCount(){
        return count;
    }

    public boolean isTarget(InstructionHandle i, UpdateData data){
        return i.getInstruction() instanceof NOP;
    }

    public UpdateType getUpdateType(InstructionHandle i){
        return UpdateType.REPLACE;
    }

    public InstructionList updateInstruction(InstructionHandle i, UpdateData data){
        count++;   // add
        return null;
    }
}

次に Generator により作成された NopDeleteProcessor を修正します.

// this class is generated by Rocinante 1.0
package jp.cafebabe.donquixote.plugins.deletenop;

import java.io.PrintWriter;
import java.net.URL;

import org.apache.bcel.classfile.JavaClass;

import jp.cafebabe.commons.bcul.updater.BytecodeUpdater;
import jp.cafebabe.donquixote.rocinante.Summary;
import jp.cafebabe.donquixote.rocinante.processors.FilterBytecodeProcessor;
import jp.cafebabe.donquixote.rocinante.summary.FormattedSummary;

public class NopDeleteProcessor extends FilterBytecodeProcessor{
    private FormattedSummary summary;
    private PrintWriter out;
    private BytecodeUpdater updater;
    private DeleteNopInstructionUpdateHandler handler;
    private int total = 0;

    public NopDeleteProcessor(BytecodeProcessor processor){
        super(processor);
    }

    @Override
    public void initialize(){
        updater = new BytecodeUpdater();
        updater.addHandler(handler = new NopDeleteInstructionUpdateHandler());

        summary = new FormattedSummary(getName());
        out = summary.getWriter();

        total = 0;
    }

    @Override
    public void perform(JavaClass target, URL location){
        ClassGen newClass = updater.update(new ClassGen(target));
        JavaClass modifiedTarget = newClass.getJavaClass();

        int count = handler.getCount();
        total += count;
        if(count > 0) out.println(target.getClassName() + ": " + count + " NOP deleted.");

        processor.perform(modifiedTarget, location);
    }

    @Override
    public Summary summarize(){
        out.println();
        out.println("Total: " + total + " NOP deleted.");

        out.close();
    }
}

最後に,src/main/resources/META-INF/plugins.xml も必要に応じて修正し てください.author-information や properties,そして,description が主 な修正箇所となると思います.

ここまで修正した後,Maven2 を使ってパッケージングすると DonQuixote プ ラグインとして動作します.