##はじめに
タイトルにもある通り、今回はEntityクラスのJavaファイルを生成するアプリを作ってみました!
OracleDB11g2R,MySQLでは動作確認済みです。
※下図の通り、結構簡単な物しか生成できませんが。。
(諸事情で@columnと@Id、@TableはJavaEEのではなく、自作したものを使用しました)
import java.util.ArrayList;
import annotation.Entity;
import annotation.Table;
import annotation.column;
import annotation.id;
@Entity
@Table("test")//DBに登録したテーブル名が表示されます
public class Test {
@id//主キー
@column//カラム
private String num;
@column//カラム
private String namename;
public void setNum(String num) {
this.num = num;
}
public String getNum() {
return this.num;
}
public void setNamename(String namename) {
this.namename = namename;
}
public String getNamename() {
return this.namename;
}
}
##環境(適当)
- 実行環境: macOS
- IDE: Eclipse
##構成(超概要)
クラス名 | 説明 |
---|---|
EntityGenerator | 下記クラスを呼び出しながら、JavaFileの生成及びファイルの中身をWriteしていくクラス |
DBReader | DBに接続し、メタデータを取得してくるクラス(テーブル一覧、カラム名、主キーetc..) |
DataTypeMapper | カラムのデータ型をDBのデータ型 → javaのデータ型に変換するクラス |
EntityInfo | DBReaderで取得してきた情報を格納するクラス |
annotation群 | @Table, @Id, @column |
##ソース |
###EntityGenerator
interface
package entityCreater.generator;
public interface EntityGenerator {
void generateEntity();
}
実装クラス
package entityCreater.generator;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import entityCreater.info.EntityInfo;
import entityCreater.reader.DBReaderImplements;
public class EntityGeneratorImplements implements EntityGenerator{
//Fileを保存する場所
String filePlace;
/**
* コンストラクタ
*/
public EntityGeneratorImplements(String filePlace) {
this.filePlace = filePlace;
}
/**
* Entity作成メソッド
*/
@Override
public void generateEntity() {
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("EntityFile作成メソッドを開始します");
ArrayList<EntityInfo> entityInfos = new DBReaderImplements().read();
for(EntityInfo ei : entityInfos) {
createFile(ei);
}
}
/**
* EntityFile作成メソッド
* @param entityInfo
*/
private void createFile(EntityInfo entityInfo) {
//DBのテーブル情報を取得
String tableName = entityInfo.getTableName();
String id = entityInfo.getId();
List<String[]> columns = entityInfo.getColumns();
//クラス名を生成
String className = tableName.substring(0, 1).toUpperCase() + tableName.substring(1).toLowerCase();
//EntityFileクラス
File entityFile = new File(filePlace + "/" + className + ".java");
try{
if (entityFile.createNewFile()){
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("ファイルの作成に成功しました。");
}else{
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("ファイルの作成に失敗しました");
}
}catch(IOException e){
System.out.println(e);
}
//Fileの中身を作成する
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("ファイルの中身を作成します。");
try(PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(entityFile, true)));) {
//Annotationのインポート文
pw.println("import annotation.Entity;");
pw.println("import annotation.Table;");
pw.println("import annotation.id;");
pw.println("import annotation.column;");
pw.println("");
//Class宣言(開始)
pw.println("@Entity");
pw.println("@Table(\"" + tableName + "\")");
pw.println("public class " + className + " {");
pw.println("");
//カラム宣言
Iterator<String[]> it = columns.iterator();
while(it.hasNext()) {
String[] colum = it.next();
//Columnの宣言
if(colum[1].equals(id)) {
pw.println(" @id");
}
pw.println(" @column");
pw.println(" private " + colum[0] + " " + colum[1] + ";");
pw.println("");
}
//Setter.Getter宣言
//Iteratorを先頭に戻す
it = columns.iterator();
while(it.hasNext()) {
String[] colum = it.next();
//Setter宣言
pw.println(" public void set" + colum[1].substring(0, 1).toUpperCase() + colum[1].substring(1).toLowerCase() + "(" + colum[0] + " " + colum[1] + ") {");
pw.println(" this." + colum[1] + " = " + colum[1] + ";");
pw.println(" }");
pw.println("");
//Getter宣言
pw.println(" public " + colum[0] + " get" + colum[1].substring(0, 1).toUpperCase() + colum[1].substring(1).toLowerCase() + "() {");
pw.println(" return this." + colum[1] + ";");
pw.println(" }");
pw.println("");
}
//Class宣言(終了)
pw.println("}");
//終了表示
System.out.println(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("*************************************************************");
System.out.println("*** SUCCESS パッケージ宣言、多重度の宣言を追記してください。 ***");
System.out.println("*************************************************************");
} catch (IOException e) {
e.printStackTrace();
}finally {
}
}
}
###DBReader
interface
package entityCreater.reader;
import java.util.ArrayList;
import entityCreater.info.EntityInfo;
public interface DBReader {
ArrayList<EntityInfo> read();
}
実装クラス
package entityCreater.reader;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Iterator;
import container.DBConfig;
import container.EnvironmentConfigReader;
import db_access.DBAccess;
import entityCreater.dataTypeMapper.DataTypeMapper;
import entityCreater.info.EntityInfo;
public class DBReaderImplements implements DBReader{
@Override
public ArrayList<EntityInfo> read() {
//metadata格納用
ResultSet rs = null;
//Table情報格納用
ArrayList<String> tableNames = new ArrayList<>();
//Entity情報格納用
ArrayList<EntityInfo> entityInfos = new ArrayList<>();
//DB設定の取得
/*
* 以下の範囲はあまり気にしないでください。
* 自作のyamlファイルからDBの接続情報(URLとかPASSWORDとか)を取得してきて、
* DBAccessクラス内部でDBとのConnectionを取得しているだけです。
* EnvironmentConfigReaderとDBAccessのソースは参考に記載しておきます
*/
/*
*ここから
*/
EnvironmentConfigReader ecr = new EnvironmentConfigReader();
DBConfig dbc = ecr.read();
String dbName = dbc.getDbName();
//コネクションの確立
DBAccess dba = new DBAccess(dbc);
/*
* ここまで
*/
try {
// データベースとの接続
Connection con = dba.getConnection();
//データベースメタデータの取得
DatabaseMetaData dbmd = con.getMetaData();
//Table名の取得
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("Table一覧を取得します");
String[] types = { "TABLE", "VIEW", "SYSTEM TABLE" };
rs = dbmd.getTables(dbName, null, "%", types);
while (rs.next()) {
String tableName = rs.getString("TABLE_NAME");
//Table名の格納
tableNames.add(tableName);
}
//Table情報の格納用クラス群
Iterator<String> tableNameList = tableNames.iterator();
String tableName;
String id = null;
ArrayList<String[]> columns;
while (tableNameList.hasNext()) {
//TableNameを取得
tableName = tableNameList.next();
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("Table名:" + tableName + "のEntityクラスを生成します");
//Tableの全column情報の取得
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("Table名:" + tableName + "の全column情報を取得します");
rs = dbmd.getColumns(dbName, null, tableName, "%");
//column格納用
columns = new ArrayList<>();
while (rs.next()) {
//SQLのデータタイプからJavaのデータタイプに変換
String dataType = DataTypeMapper.dataTypeChange(rs.getString("TYPE_NAME"));
//変数名を小文字に変換
String columnName = rs.getString("COLUMN_NAME").toLowerCase();
String[] column = { dataType, columnName };
columns.add(column);
}
//PrimaryKeyを取得
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("Table名:" + tableName + "のPrimaryKeyを取得します");
ResultSet primaryKeys = dbmd.getPrimaryKeys(dbName, null, tableName);
if (primaryKeys.next()) {
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("Table名:" + tableName + "のPrimaryKeyは " + primaryKeys.getString("COLUMN_NAME") + "です");
id = primaryKeys.getString("COLUMN_NAME").toLowerCase();
}
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("EntityInfoクラスにTable情報を格納しています");
//Table情報格納用クラス
EntityInfo ei = new EntityInfo();
//Table情報格納用クラスにTableNameを設定
ei.setTableName(tableName);
//Table情報格納用クラスにidを設定
ei.setId(id);
//Table情報格納クラスにカラム情報を設定
ei.setColumns(columns);
entityInfos.add(ei);
}
rs.close();
// データベースのクローズ
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("DBとのコネクションを破棄します");
con.close();
} catch (Exception e) {
System.out.println("Exception発生");
e.printStackTrace();
}
return entityInfos;
}
}
###DataTypeMapper
package entityCreater.dataTypeMapper;
public class DataTypeMapper {
/**
* SQLのデータタイプからJavaのデータタイプに変換するクラス
* @param sqlDataType
* @return
*/
public static String dataTypeChange(String sqlDataType) {
String javaDataType = null;
switch (sqlDataType) {
case "CHAR":
case "VARCHAR":
case "LONGVARCHAR":
javaDataType = "String";
break;
case "NUMERIC":
case "DECIMAL":
javaDataType = "java.math.BigDecimal";
break;
case "BIT":
javaDataType = "boolean";
break;
case "TINYINT":
javaDataType = "byte";
break;
case "SMALLINT":
javaDataType = "short";
break;
case "INTEGER":
case "INT":
javaDataType = "Integer";
break;
case "BIGINT":
javaDataType = "long";
break;
case "REAL":
javaDataType = "float";
break;
case "FLOAT":
case "DOUBLE":
javaDataType = "double";
break;
case "BINARY":
case "VARBINARY":
case "LONGVARBINARY":
javaDataType = "byte[]";
break;
case "DATE":
javaDataType = "java.sql.Date";
break;
case "TIME":
javaDataType = "java.sql.Time";
break;
case "TIMESTAMP":
javaDataType = "java.sql.Timestamp";
break;
default:
break;
}
return javaDataType;
}
}
###EntityInfo
package entityCreater.info;
import java.util.List;
/**
*
* Entity情報格納クラス
* @author okamotoyuuma
*
*/
public class EntityInfo {
//テーブル名
private String tableName;
//Primary Key名
private String id;
//すべてのカラム名と型
private List<String[]> columns;
/**
* (non-javadoc)
* getter setter
* @return
*/
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<String[]> getColumns() {
return columns;
}
public void setColumns(List<String[]> columns) {
this.columns = columns;
}
}
###アノテーション
@Tableアノテーション(属性にテーブル名を格納するクラス)
package annotation;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Target(TYPE)
@Retention(RUNTIME)
public @interface Table {
String value();
}
@idアノテーション(主キーのフィールドに付与する)
package annotation;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(FIELD)
public @interface id {
}
@columnnアノテーション(テーブルのカラム値に付与する)
package annotation;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(FIELD)
public @interface column {
}
##使い方
適当にMainメソッドを作って、下記のように生成するEntityクラスを格納する場所を指定すればOKです!
public class main {
public static void main(String[] args) {
EntityGenerator eg = new EntityGeneratorImplements("保存先のパス");
eg.generateEntity();
}
}
##最後に
今回はEntityクラスの自動生成をしてみました。
ソースやロジック等はまだまだ未熟で稚拙ですが、File生成はしたことがなかったのでとても良い経験になりました!
考慮できていない点や、ソースの改善点などご指摘あればコメントでいただけますと幸いです。
以下の参考項に上記ソースに載せていないDB設定ファイルや読み込むクラス等を載せていますので
興味ある方はみていただけたらと思います。
##参考(DB設定YAMLファイルと設定ファイルを読み込むクラスなど)
DB設定ファイル
#DBの設定
!!container.DBConfig #DB定義設定クラスのパス
driver: com.mysql.cj.jdbc.Driver #driver名
url: jdbc:mysql://localhost:3306/DB名 #DBのURL
user: DBのユーザ名 #DBのユーザ
password: password #DBのパスワード
numberOfAccess: 10 #コネクションの数
dbName: データベース名 #DB名
dbType: MySQL #DBの種類(今回対応するのはMySQLとOracleDBのみ)
schema: スキーマ名
※DB設定ファイルは別のアプリでも使っているため、余計な情報も入ってます。。
設定情報を格納するためのクラス
package container;
//データベースの設定ファイル
public class DBConfig {
//ドライバ名
String driver;
//DBのURL
String url;
//DBのユーザ
String user;
//パスワード
String password;
//スキーマ名
String schema;
//コネクションの確立数
int numberOfAccess;
//DBName
String dbName;
//DBType
String dbType;
public String getDriver() {
return driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public int getNumberOfAccess() {
return numberOfAccess;
}
public void setNumberOfAccess(int numberOfAccess) {
this.numberOfAccess = numberOfAccess;
}
public String getDbName() {
return dbName;
}
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getDbType() {
return dbType;
}
public void setDbType(String dbType) {
this.dbType = dbType;
}
}
上記設定ファイルを読み込むEnvironmentConfigReaderクラス
package container;
import org.yaml.snakeyaml.Yaml;
public class EnvironmentConfigReader implements Reader<DBConfig>{
//DBの設定ファイル
static String configFileName = "DBProfile.yaml";
//yamlファイルからDB設定を取得するメソッド(引数なし)
@Override
public DBConfig read() {
//ログ発生箇所
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
//処理内容
System.out.println(configFileName + "の読み込みを開始します。");
Yaml yaml = new Yaml();
DBConfig dbc = (DBConfig) yaml.load(getClass().getResourceAsStream(configFileName));
//ログ発生箇所
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
//処理内容
System.out.println(configFileName + "の読み込みが完了しました。");
return dbc;
}
//yamlファイルからDB設定を取得するメソッド(引数あり)
@Override
public DBConfig read(String setConfigFileName) {
//ログ発生箇所
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
//処理内容
System.out.println(configFileName + "の読み込みを開始します。");
//指定されたファイル名をセット
if (configFileName != null) {
configFileName = setConfigFileName;
}
Yaml yaml = new Yaml();
DBConfig dbc = (DBConfig) yaml.load(getClass().getResourceAsStream(configFileName));
//ログ発生箇所
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
//処理内容
System.out.println(configFileName + "の読み込みが完了しました。");
return dbc;
}
}
DBとのコネクションを格納するクラス
package db_access;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import container.DBConfig;
public class DBAccess {
//メンバ
private Connection conn = null;
public DBAccess(DBConfig dbc) {
try {
Class.forName(dbc.getDriver());
conn = DriverManager.getConnection(dbc.getUrl(), dbc.getUser(), dbc.getPassword());
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("DBに接続しました");
//自動コミットOFF
conn.setAutoCommit(false);
} catch (SQLException | ClassNotFoundException e) {//コネクションの確立に失敗
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("DBとの接続に失敗しました");
e.printStackTrace();
}
}
//コネクションを配布する
public Connection getConnection() {
return conn;
}
//コネクションの破棄
public void closeConnection() {
try {
conn.close();
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("DBから切断しました");
} catch (SQLException e) {
// TODO 自動生成された catch ブロック
System.out.print(Thread.currentThread().getStackTrace()[1].getClassName() + ":");
System.out.println("DBから切断できませんでした");
e.printStackTrace();
}
}
}