top / index / prev / next / target / source
日記形式でつづる いがぴょんコラム ウェブページです。
Apache iBatis の sqlMap.xml ファイルを入力して、Javaソースコードを自動生成する blancoIBatis というプロダクトを新規作成しました。最初の機能として、sqlMap.xml から、検索結果の行をあらわすバリューオブジェクトの Javaソースコードを自動生成する機能を実装しました。
Apache iBatis の sqlMap.xml ファイルを入力して、Javaソースコードを自動生成する blancoIBatis というプロダクトを新規作成しました。最初の機能として、sqlMap.xmlから、検索結果の行をあらわすバリューオブジェクトの Javaソースコードを自動生成する機能を実装しました。(Apache Antタスクのみの提供です)
Apache iBaits を利用していて、検索結果のバリューオブジェクトを自前で準備することに不満を感じたことはありませんか? その疑問はとても正しいものです。そして、blancoIBatisを利用すると、そういったバリューオブジェクトは sqlMap.xml ファイルに記述された SQL文から自動生成することができるのです。技術的には、SQL文の実行結果から得られる情報によって、フィールド名および型名を解決して実現しています。
ご存知かも知れませんが、Apache iBatis のサブプロダクトとして Apache IBATOR という自動生成系があります。ところが残念なことに IBATOR は DBスキーマからの自動生成をサポートするプロダクトです。sqlMap.xmlファイルにかかれた SQL文から自動生成をおこなうものではありません。一方で iBatis の利用者の多くは、DBスキーマから自動生成された SQL文で目的のプログラムを実現することができる場合は少ないようです。SQLを自前で手書きする必要があるからこそ iBatis を採用していることが多いからです。手書きで SQLを書かなくてはならない、そういった人たち向けの Javaソースコード自動生成を実現するのが blancoIBatis なのです。
とはいえ、このプロダクトは、非常にニッチなところを狙ったものです。ほとんどの人には役に立たないことでしょう。(なぜなら、多くの人たちは、やはり別系統の自動生成系を利用しているだろうからです。何の自動生成系の支援も受けずに生で iBatis を利用している人は少ない、ですよね!) そのため、現状では説明もほとんど付けていません。一方で、現時点では 実行行数 200行程度のプロダクトなので、もしその気になればソースコードから簡単に仕様を理解することもできます。(と想定していますが、もし blancoIBatis へのニーズを感じる人は連絡や要望をお寄せ下さい。要望が多いようでしたら、ドキュメントなどを強化していきます)
なお、blancoIBatis の自動生成は、iBatis の仕様上の制約から、一部不完全なものとなります。sqlMap.xml では、どうしても情報が不足してしまうケースがあるのです。(sqlMap.xmlの記述内容によっては、ほぼ完全な自動生成も実現できますが…) もし、より完全な自動生成を利用したい場合には、blancoDbの利用を検討することを強く推奨します。iBatis と blancoDb とは かなり仕様が似ていますが、blancoDb のほうが、より完全な自動生成環境を実現することができます。
2008.12.11追記 iBatis の デモ・アプリケーションである JPetStore の sqlMap.xml から バリューオブジェクトを自動生成した際の例を示します。
入力となる sqlMap.xml は以下のようになります。実際には幾つかの SQL が記載されていますが、ここでは 1つだけに注目します。 Item.xml (自動生成で利用される入力情報)
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd"><sqlMap namespace="Item">
<typeAlias alias="item" type="com.ibatis.jpetstore.domain.Item"/>
…略…
<cacheModel id="quantityCache" type="LRU">
<flushInterval hours="24"/>
<flushOnExecute statement="updateInventoryQuantity"/>
<property name="size" value="100"/>
</cacheModel>
…略…
<select id="getItem" resultClass="item" parameterClass="string" cacheModel="quantityCache">
select
I.ITEMID,
LISTPRICE,
UNITCOST,
SUPPLIER AS supplierId,
I.PRODUCTID AS "product.productId",
NAME AS "product.name",
DESCN AS "product.description",
CATEGORY AS "product.categoryId",
STATUS,
ATTR1 AS attribute1,
ATTR2 AS attribute2,
ATTR3 AS attribute3,
ATTR4 AS attribute4,
ATTR5 AS attribute5,
QTY AS quantity
from ITEM I, INVENTORY V, PRODUCT P
where P.PRODUCTID = I.PRODUCTID
and I.ITEMID = V.ITEMID
and I.ITEMID = #value#
</select>
…略…</sqlMap>
この sqlMap.xml から、以下のような Javaソースコードを自動生成することができます。
検索結果の列についての列名や型情報が JavaDoc に埋め込まれているのが特徴です。
この自動生成結果の例は PostgreSQL 8.3 における実行結果です。他の RDBMS や異なるバージョンで動作させると 自動生成結果にも変化がみられる場合があります。
実際には、、、
JPetStore の Item.xml からは 3つの Javaソースコードが自動生成されます。
Item.xml の SQLそのものに微妙なバグ (あいまいな列) があったので、それを修正した上で動作させています。
GetItemRow.java (自動生成される Javaソースコード)
/*
* このソースコードは blanco Frameworkにより自動生成されました。
*/
package blanco.sample;
import java.math.BigDecimal;
/**
* sqlMap id [getItem] の検索結果の行オブジェクト。\n <select id="getItem" resultClass="blanco.sample.GetItemRow" ...
*/
public class GetItemRow {
/**
* SQL検索結果の列: [itemid]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
* フィールド: [itemid]。
*/
private String fItemid;
/**
* SQL検索結果の列: [listprice]。
*
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
* フィールド: [listprice]。
*/
private BigDecimal fListprice;
/**
* SQL検索結果の列: [unitcost]。
*
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
* フィールド: [unitcost]。
*/
private BigDecimal fUnitcost;
/**
* SQL検索結果の列: [supplierid]。
*
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [Nullable]。
* フィールド: [supplierid]。
*/
private Integer fSupplierid;
/**
* SQL検索結果の列: [product.productId]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
* フィールド: [product.productId]。
*/
private String fProductProductId;
/**
* SQL検索結果の列: [product.name]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [product.name]。
*/
private String fProductName;
/**
* SQL検索結果の列: [product.description]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [255]。
* NULL: [Nullable]。
* フィールド: [product.description]。
*/
private String fProductDescription;
/**
* SQL検索結果の列: [product.categoryId]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
* フィールド: [product.categoryId]。
*/
private String fProductCategoryId;
/**
* SQL検索結果の列: [status]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [2]。
* NULL: [Nullable]。
* フィールド: [status]。
*/
private String fStatus;
/**
* SQL検索結果の列: [attribute1]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [attribute1]。
*/
private String fAttribute1;
/**
* SQL検索結果の列: [attribute2]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [attribute2]。
*/
private String fAttribute2;
/**
* SQL検索結果の列: [attribute3]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [attribute3]。
*/
private String fAttribute3;
/**
* SQL検索結果の列: [attribute4]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [attribute4]。
*/
private String fAttribute4;
/**
* SQL検索結果の列: [attribute5]。
*
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
* フィールド: [attribute5]。
*/
private String fAttribute5;
/**
* SQL検索結果の列: [quantity]。
*
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [NoNulls]。
* フィールド: [quantity]。
*/
private int fQuantity;
/**
* フィールド [itemid] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [itemid]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @param argItemid フィールド[itemid]に設定する値。
*/
public void setItemid(final String argItemid) {
fItemid = argItemid;
}
/**
* フィールド [itemid] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [itemid]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @return フィールド[itemid]から取得した値。
*/
public String getItemid() {
return fItemid;
}
/**
* フィールド [listprice] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [listprice]。]。
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @param argListprice フィールド[listprice]に設定する値。
*/
public void setListprice(final BigDecimal argListprice) {
fListprice = argListprice;
}
/**
* フィールド [listprice] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [listprice]。]。
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @return フィールド[listprice]から取得した値。
*/
public BigDecimal getListprice() {
return fListprice;
}
/**
* フィールド [unitcost] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [unitcost]。]。
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @param argUnitcost フィールド[unitcost]に設定する値。
*/
public void setUnitcost(final BigDecimal argUnitcost) {
fUnitcost = argUnitcost;
}
/**
* フィールド [unitcost] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [unitcost]。]。
* TYPE_NAME: [numeric]。
* DATA_TYPE_DISPLAY_NAME: [NUMERIC]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @return フィールド[unitcost]から取得した値。
*/
public BigDecimal getUnitcost() {
return fUnitcost;
}
/**
* フィールド [supplierid] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [supplierid]。]。
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @param argSupplierid フィールド[supplierid]に設定する値。
*/
public void setSupplierid(final Integer argSupplierid) {
fSupplierid = argSupplierid;
}
/**
* フィールド [supplierid] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [supplierid]。]。
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [Nullable]。
*
* @return フィールド[supplierid]から取得した値。
*/
public Integer getSupplierid() {
return fSupplierid;
}
/**
* フィールド [product.productId] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [product.productId]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @param argProductProductId フィールド[product.productId]に設定する値。
*/
public void setProductProductId(final String argProductProductId) {
fProductProductId = argProductProductId;
}
/**
* フィールド [product.productId] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [product.productId]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @return フィールド[product.productId]から取得した値。
*/
public String getProductProductId() {
return fProductProductId;
}
/**
* フィールド [product.name] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [product.name]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argProductName フィールド[product.name]に設定する値。
*/
public void setProductName(final String argProductName) {
fProductName = argProductName;
}
/**
* フィールド [product.name] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [product.name]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[product.name]から取得した値。
*/
public String getProductName() {
return fProductName;
}
/**
* フィールド [product.description] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [product.description]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [255]。
* NULL: [Nullable]。
*
* @param argProductDescription フィールド[product.description]に設定する値。
*/
public void setProductDescription(final String argProductDescription) {
fProductDescription = argProductDescription;
}
/**
* フィールド [product.description] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [product.description]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [255]。
* NULL: [Nullable]。
*
* @return フィールド[product.description]から取得した値。
*/
public String getProductDescription() {
return fProductDescription;
}
/**
* フィールド [product.categoryId] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [product.categoryId]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @param argProductCategoryId フィールド[product.categoryId]に設定する値。
*/
public void setProductCategoryId(final String argProductCategoryId) {
fProductCategoryId = argProductCategoryId;
}
/**
* フィールド [product.categoryId] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [product.categoryId]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @return フィールド[product.categoryId]から取得した値。
*/
public String getProductCategoryId() {
return fProductCategoryId;
}
/**
* フィールド [status] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [status]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [2]。
* NULL: [Nullable]。
*
* @param argStatus フィールド[status]に設定する値。
*/
public void setStatus(final String argStatus) {
fStatus = argStatus;
}
/**
* フィールド [status] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [status]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [2]。
* NULL: [Nullable]。
*
* @return フィールド[status]から取得した値。
*/
public String getStatus() {
return fStatus;
}
/**
* フィールド [attribute1] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [attribute1]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argAttribute1 フィールド[attribute1]に設定する値。
*/
public void setAttribute1(final String argAttribute1) {
fAttribute1 = argAttribute1;
}
/**
* フィールド [attribute1] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [attribute1]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[attribute1]から取得した値。
*/
public String getAttribute1() {
return fAttribute1;
}
/**
* フィールド [attribute2] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [attribute2]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argAttribute2 フィールド[attribute2]に設定する値。
*/
public void setAttribute2(final String argAttribute2) {
fAttribute2 = argAttribute2;
}
/**
* フィールド [attribute2] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [attribute2]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[attribute2]から取得した値。
*/
public String getAttribute2() {
return fAttribute2;
}
/**
* フィールド [attribute3] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [attribute3]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argAttribute3 フィールド[attribute3]に設定する値。
*/
public void setAttribute3(final String argAttribute3) {
fAttribute3 = argAttribute3;
}
/**
* フィールド [attribute3] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [attribute3]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[attribute3]から取得した値。
*/
public String getAttribute3() {
return fAttribute3;
}
/**
* フィールド [attribute4] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [attribute4]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argAttribute4 フィールド[attribute4]に設定する値。
*/
public void setAttribute4(final String argAttribute4) {
fAttribute4 = argAttribute4;
}
/**
* フィールド [attribute4] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [attribute4]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[attribute4]から取得した値。
*/
public String getAttribute4() {
return fAttribute4;
}
/**
* フィールド [attribute5] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [attribute5]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @param argAttribute5 フィールド[attribute5]に設定する値。
*/
public void setAttribute5(final String argAttribute5) {
fAttribute5 = argAttribute5;
}
/**
* フィールド [attribute5] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [attribute5]。]。
* TYPE_NAME: [varchar]。
* DATA_TYPE_DISPLAY_NAME: [VARCHAR]。
* サイズ: [80]。
* NULL: [Nullable]。
*
* @return フィールド[attribute5]から取得した値。
*/
public String getAttribute5() {
return fAttribute5;
}
/**
* フィールド [quantity] の値を設定します。
*
* フィールドの説明: [SQL検索結果の列: [quantity]。]。
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @param argQuantity フィールド[quantity]に設定する値。
*/
public void setQuantity(final int argQuantity) {
fQuantity = argQuantity;
}
/**
* フィールド [quantity] の値を取得します。
*
* フィールドの説明: [SQL検索結果の列: [quantity]。]。
* TYPE_NAME: [int4]。
* DATA_TYPE_DISPLAY_NAME: [INTEGER]。
* サイズ: [10]。
* NULL: [NoNulls]。
*
* @return フィールド[quantity]から取得した値。
*/
public int getQuantity() {
return fQuantity;
}
/**
* このバリューオブジェクトの文字列表現を取得します。
*
* 使用上の注意
* <UL>
* <LI>オブジェクトのシャロー範囲のみ文字列化の処理対象となります。
* <LI>オブジェクトが循環参照している場合には、このメソッドは使わないでください。
* </UL>
*
* @return バリューオブジェクトの文字列表現。
*/
public String toString() {
final StringBuffer buf = new StringBuffer();
buf.append("blanco.sample.GetItemRow[");
buf.append("itemid=" + fItemid);
buf.append(",listprice=" + fListprice);
buf.append(",unitcost=" + fUnitcost);
buf.append(",supplierid=" + fSupplierid);
buf.append(",product.productId=" + fProductProductId);
buf.append(",product.name=" + fProductName);
buf.append(",product.description=" + fProductDescription);
buf.append(",product.categoryId=" + fProductCategoryId);
buf.append(",status=" + fStatus);
buf.append(",attribute1=" + fAttribute1);
buf.append(",attribute2=" + fAttribute2);
buf.append(",attribute3=" + fAttribute3);
buf.append(",attribute4=" + fAttribute4);
buf.append(",attribute5=" + fAttribute5);
buf.append(",quantity=" + fQuantity);
buf.append("]");
return buf.toString();
}
}