Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

Java | 流れるようなデータクラス生成ツール

パンくず

Java
流れるようなデータクラス生成ツール

概要

流れるようなデータクラス生成ツールについて

要件

定義用クラスに以下の内容を指定
・データクラス名
・データクラスJavaDoc
・データクラスJavaDoc用author
・フィールドコメントのリスト
・フィールドデータ型のリスト
・フィールド変数名のリスト

上記の内容を元に任意のクラス名で、任意の数のフィールドと流れるようなインターフェースを持つ
データクラスを生成する。

クラス構成

develop_util.fluentifgen
│ FluentIfGenerator.java
│ FluentIfGeneratorExecutor.java

├─conf(設定ファイル)
│ FluentIfDefinitionIntf.java
│ HogeTestFixture.java

└─sample(出力サンプル)
Hoge.java

コード

自動生成処理本体
FluentIfGenerator.java

package develop_util.fluentifgen;

import develop_util.fluentifgen.conf.FluentIfDefinitionIntf;

public class FluentIfGenerator {
  private static String template = "";
  public static final String CLASS_NAME = "$CLASS_NAME$";
  public static final String JAVADOC_CLASS_NAME = "$class_comment$";
  public static final String JAVADOC_AUTHOR = "$author$";
  public static final String FIELDS = "$fields$";
  public static final String SETTERS = "$setters$";

  static {
    template += "/**\n";
    template += "* " + FluentIfGenerator.JAVADOC_CLASS_NAME + "\n";
    template += "* \n";
    template += "* @author " + FluentIfGenerator.JAVADOC_AUTHOR + "\n";
    template += "* \n";
    template += "*/\n";
    template += "public static class " + FluentIfGenerator.CLASS_NAME + " {\n";
    template += FluentIfGenerator.FIELDS + "\n";
    template += FluentIfGenerator.SETTERS + "\n";
    template += "      public String toString() {\n";
    template += "      // Fixtureの内容を一括出力\n";
    template += "      return CommonUtil.getAllFiledInfo(Fixture.class, this);\n";
    template += "      }\n";
    template += "}\n";
  }

  public static void generate(FluentIfDefinitionIntf definition) {
    String out = template;

    out = out.replace(FluentIfGenerator.CLASS_NAME, definition.getOutputClassName());
    out = out.replace(FluentIfGenerator.JAVADOC_CLASS_NAME, definition.getOutputClassJavaDoc());
    out = out.replace(FluentIfGenerator.JAVADOC_AUTHOR, definition.getAuthor());

    StringBuilder field = new StringBuilder();
    // Fieldの生成
    for (int i = 0; i < definition.getFieldComments().size(); i++) {
      field.append("/** ");
      field.append(definition.getFieldComments().get(i));
      field.append(". */\n");
      field.append(definition.getTypes().get(i) + " ");
      field.append(definition.getFieldNames().get(i) + ";\n");
    }
    out = out.replace(FluentIfGenerator.FIELDS, field);

    StringBuilder setter = new StringBuilder();
    // Setterの生成
    for (int i = 0; i < definition.getFieldNames().size(); i++) {
      String fieldName = definition.getFieldNames().get(i);
      setter.append("public " + definition.getOutputClassName() + " " + fieldName + "(" + definition.getTypes().get(i)
          + " " + fieldName + ") {\n");
      setter.append("this." + fieldName + "=" + fieldName + ";\n");
      setter.append("return this;\n");
      setter.append("}\n");
    }
    out = out.replace(FluentIfGenerator.SETTERS, setter);
    System.out.println(out);
  }
}

自動生成機能呼び出しコード
FluentIfGeneratorExecutor

package develop_util.fluentifgen;

import develop_util.fluentifgen.conf.HogeTestFixture;

public class FluentIfGeneratorExecutor {
  public static void main(String args[]) {
    FluentIfGenerator.generate(new HogeTestFixture());
  }
}

自動生成内容定義用インターフェース
FluentIfDefinitionIntf

package develop_util.fluentifgen.conf;

import java.util.List;

public interface FluentIfDefinitionIntf {
  static final String DEFAULT_CLASS_NAME = "Fixture";

  /**
   * 出力クラス名を指定する。
   * @return 出力クラス名
   */
  String getOutputClassName();

  /**
   * 出力クラスJavaDoc概要を指定する。
   * @return 出力クラスJavaDoc概要
   */
  String getOutputClassJavaDoc();

  /**
   * 作成者を指定する。
   * @return 作成者
   */
  String getAuthor();

  /**
   * フィールドのコメントを列挙する。
   *
   * @return フィールドのコメントリスト
   */
  List<String> getFieldComments();

  /**
   * フィールドのデータ型を列挙する。
   *
   * @return フィールドのデータ型のリスト
   */
  List<String> getTypes();

  /**
   * フィールドの変数名を列挙する。
   *
   * @return フィールド名のリスト
   */
  List<String> getFieldNames();
}

自動生成内容定義ファイル(Fixture出力設定例)
HogeTestFixture

package develop_util.fluentifgen.conf;

import java.util.Arrays;
import java.util.List;

public class HogeTestFixture implements FluentIfDefinitionIntf {

  @Override
  public String getOutputClassName() {
    return FluentIfDefinitionIntf.DEFAULT_CLASS_NAME;
  }

  @Override
  public String getOutputClassJavaDoc() {
    return "HogeTestのFixture";
  }

  @Override
  public String getAuthor() {
    return "tbpgr";
  }

  @Override
  public List<String> getFieldComments() {
    List<String> fieldComments = Arrays.asList("ケース番号","年齢","名前");
    return fieldComments;
  }

  @Override
  public List<String> getTypes() {
    List<String> fieldTypes = Arrays.asList("int","int","String");
    return fieldTypes;
  }

  @Override
  public List<String> getFieldNames() {
    List<String> fieldNames = Arrays.asList("caseNo","age","name");
    return fieldNames;
  }

}

出力

※出力内容をフォーマットした内容

  /**
   * HogeTestのFixture
   *
   * @author tbpgr
   *
   */
  public static class Fixture {
    /** ケース番号. */
    int caseNo;
    /** 年齢. */
    int age;
    /** 名前. */
    String name;

    public Fixture caseNo(int caseNo) {
      this.caseNo = caseNo;
      return this;
    }

    public Fixture age(int age) {
      this.age = age;
      return this;
    }

    public Fixture name(String name) {
      this.name = name;
      return this;
    }

    public String toString() {
      // Fixtureの内容を一括出力
      return CommonUtil.getAllFiledInfo(Fixture.class, this);
    }
  }

出力内容を適用

出力されたデータクラスをHogeクラスに貼り付けて利用してみます。

package develop_util.fluentifgen.sample;

import gr.java_conf.tb.tbpg_util.common.CommonUtil;

import java.util.Arrays;
import java.util.List;

public class Hoge {
  public static void main(String args[]) {
    Fixture tanaka = new Fixture().caseNo(1).age(20).name("田中");
    Fixture sato = new Fixture().caseNo(2).age(24).name("佐藤");
    Fixture suzuki = new Fixture().caseNo(3).age(100).name("鈴木");
    List<Fixture> fixtures = Arrays.asList(tanaka, sato, suzuki);

    for (Fixture fixture : fixtures) {
      System.out.println(CommonUtil.getAllFiledInfo(Fixture.class, fixture));
    }
  }

  /**
   * HogeTestのFixture
   *
   * @author tbpgr
   *
   */
  public static class Fixture {
    /** ケース番号. */
    int caseNo;
    /** 年齢. */
    int age;
    /** 名前. */
    String name;

    public Fixture caseNo(int caseNo) {
      this.caseNo = caseNo;
      return this;
    }

    public Fixture age(int age) {
      this.age = age;
      return this;
    }

    public Fixture name(String name) {
      this.name = name;
      return this;
    }

    public String toString() {
      // Fixtureの内容を一括出力
      return CommonUtil.getAllFiledInfo(Fixture.class, this);
    }
  }

}

利用例の出力

int|caseNo|1
int|age|20
class java.lang.String|name|田中


int|caseNo|2
int|age|24
class java.lang.String|name|佐藤


int|caseNo|3
int|age|100
class java.lang.String|name|鈴木