UIX開発者ガイド | ![]() 目次 |
![]() 前へ |
![]() 次へ |
このトピックでは、ノード・ツリー自体は変更せずに、uiXMLのデータ・バインド要素およびUIX ComponentsのBoundValue
インタフェースを使用して、ユーザーごとに動的コンテンツを生成するページの作成方法を説明します。また、DataObject
インタフェースを使用してデータをグループ化する方法や、DataObject
をBoundValue
、UIX Components BeanおよびuiXMLのページで使用可能にする方法について説明します。さらに、DataObjectList
インタフェースおよび現在のDataObject
を使用した、UIX Componentsによるデータ反復処理のサポート方法についても説明します。最後に、DataObject
およびDataObjectList
をuiXMLに直接作成する方法を説明します。
ここでは、次の項目について説明します。
BoundValue
インタフェースは、UIX Componentsの動的ページにとって不可欠です。これは、次のようにRenderingContext
が渡され、任意のJavaオブジェクトが返される1つのメソッドで構成されています。
public interface oracle.cabo.ui.data.BoundValue
{
public Object getValue(RenderingContext context);
}
この単純なインタフェースが便利なのは、すべてのUIX Components Beanであらゆる属性値のかわりに使用できるためです。属性の値がBoundValueに設定されている場合、その属性の値を取得しようとしてもBoundValueは返されません。UIX ComponentsではBoundValue.getValue()
をコールし、結果を返します。次に例を示します。
// Remember the code to set the text of a StyledTextBean...
styledTextBean.setText("Some text");
// ... is really a cover for:
styledTextBean.setAttributeValue(UIConstants.TEXT_ATTR,
"Some text");
// So you can also set a BoundValue:
BoundValue boundValue = ...;
styledTextBean.setAttributeValue(UIConstants.TEXT_ATTR,
boundValue);
この後、表示時にStyledTextBeanのテキストを要求する場合、次のように指定します。
text = styledTextBean.getAttributeValue(renderingContext,
UIConstants.TEXT_ATTR)
// .. is equivalent to writing:
BoundValue boundValue = ...;
text = boundValue.getValue(renderingContext);
setAttributeValue()
でBoundValue
を使用して、すべての属性をデータ・バインドできることを覚えておいてください。属性のデータ・バインドのための専用のメソッドがそのBeanにあるかどうか、以前にその属性がデータ・バインドされたかどうか、あるいはその属性が必要とするJavaオブジェクトのタイプはどれかなどは関係ありません。すべての属性をデータ・バインドできます。
多くのBeanで、属性をバインドするための便利なメソッドが用意されています。StyledTextBean
のtext属性もその1つです。次のように記述できます。
BoundValue boundValue = ...;
styledTextBean.setTextBinding(boundValue);
ただし、これは利便性が高いというだけです。便利なメソッドがあるかどうかにかかわらず、すべてのBeanですべての属性をバインドできます。
BoundValue
には多数の実装が用意されていますが、次にカスタムの実装について説明します。次のコードでは常に現在の日付が返されます。
public class CurrentDate implements BoundValue
{
public Object getValue(RenderingContext context)
{
return new Date();
}
}
これをDateFieldBean
で使用します。
DateFieldBean dateField = new DateFieldBean();
dateField.setValueBinding(new CurrentDate());
上の例で生成される日付フィールドは、常に現在の日付で初期化されます。上のコードは次のコードとよく似ています。
DateFieldBean dateField = new DateFieldBean();
dateField.setValue(new Date());
ただし大きな違いがあります。2番目の例では日付の設定は1回です。Beanを1回だけ使用して解放する場合は、問題ありません。ただし、UIX ComponentsではBeanは何度も再利用できます。最初の例で使用したBoundValue
の場合、UIX Componentsにより、ページのレンダリングのたびに日付が要求されます。このため、DateFieldBean
が作成された後でも常に正確な月日が表示されます。
重要なデータのバインドについてまだ説明していません。たとえば、uiXMLでの例を示していません。また、RenderingContext
がgetValue()
に渡される理由も説明していません。ここで、uiXMLおよびビルトインのBoundValue
について説明します。
uiXMLでは、BoundValue
は<boundAttribute>
要素によって設定されます。この要素にはname属性があり、これによってバインドされる属性の名前が設定されます。使用するBoundValue
を定義する1つの子要素もあります。
<link text="Static link text">
<boundAttribute name="destination">
<!-- The BoundValue goes here... -->
</boundAttribute>
</link>
ここでは、リンクUINodeを作成しました。text属性は固定ですが、destinationにはバインド先が必要です。次に、BoundValueのUIX要素を作成して、バインド先を指定します。
<link text="Static link text">
<boundAttribute name="destination">
<contextProperty xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
select="ctrl:baseURI"/>
</boundAttribute>
</link>
これで、BoundValue
の要素を定義できました。<contextProperty>
によって定義されたBoundValue
の種類を説明するために、さらに2つのRenderingContext
メソッドを使用します。
public interface RenderingContext
{
// ...
public Object getProperty(String namespace, Object key);
public void setProperty(String namespace, Object key, Object value);
// ...
}
これらのRenderingContext
メソッドを使用して、任意の数の値を格納できます。前に説明したUINodeネームスペースの場合のように、ここでも競合を回避するためにネームスペースを使用します。独自のネームスペース内にプロパティを設定すると、UIX Componentsのビルトイン・ネームスペースを上書きする心配がありません。
ここで、再び<contextProperty>
の例を参照します。
<contextProperty xmlns:ctrl="http://xmlns.oracle.com/uix/controller"
select="ctrl:baseURI"/>
ここでは、ctrlネームスペースを定義しました。UIX ComponentsおよびuiXMLのビルトイン・サポートを備えたWebアプリケーション・フレームワーク、UIX Controller用のURLが指定されています。UIXサポートの一部として、ネームスペース内にいくつかのRenderingContext
プロパティが設定されています。その1つがbaseURI、つまりサーブレットを実行するWebサーバーを示すURLです。
また、select属性も定義しました。この属性では、RenderingContext
から取得するプロパティのネームスペースおよび名前を指定します。この例では、UIX ControllerのネームスペースおよびbaseURI名を要求しています。
ContextPropertyBoundValue
は便利ですが、Beanに動的データを取り込む最適な方法ではありません。1つには、必要となるすべての値をRenderingContext
に渡す必要があるためです。
役に立つBoundValue
は他にも多数あります。たとえば、<concat>
を使用すると、複数の文字列(動的文字列および静的文字列を含む)を1つの文字列に連結できます。しかし、動的データにとって最も重要なBoundValue
はDataBoundValue
です。そのため、ここでDataObject
について説明します。
DataObject
Javaインタフェースは、UIX ComponentsおよびuiXMLのページの汎用データソースです。DataObject
を使用して、Javaバック・エンドをUIXユーザー・インタフェースに接続します。DataObjectは、1つのメソッドのみを含む、非常に単純な新たなインタフェースです。
public interface oracle.cabo.ui.data.DataObject
{
/**
* Select a single value out of the DataObject.
* @param context the current RenderingContext
* @param select a select key
* @return the selected value
*/
public Object selectValue(RenderingContext context, Object select);
}
DataObject
インタフェースは、BoundValue
インタフェースによく似ていますが、RenderingContext
以外のものも使用します。select
オブジェクトも使用します。つまり、多数の異なるデータに対して1つのDataObject
を要求できます。DataObject
には一連のデータが含まれています。この意味ではHashtable
またはMap
によく似ていますが、DataObject
は小規模のインタフェースであり、開発者またはデータ構造に対する要件はごくわずかです。そのため、次のような任意のデータ形式に容易に適応できます。
UIXには、BC4Jへのビルトイン・バインド(「Business Components for Javaの統合」を参照)と、「より簡単な方法: Beansへのバインド」で後述するJavaBeansへのビルトイン・バインドが組み込まれています。
ほとんどの開発者は、最初にselect
パラメータを目にした際にHashtable
のキーを想定するでしょうが、DataObject
はそのようには機能しません。select
パラメータは次のいずれかになります。
Integer
インデックス DataObject
の最も単純な実装は、DictionaryData
クラスです。データを直接DataObject
に渡すことが可能で、Hashtable
をDataObject
に変換することもできます。
例:
// Build up information about an employee
DictionaryData data = new DictionaryData();
data.put("empName", "Joe Smith");
data.put("manager", "Larry Ellison");
data.put("ID", "12345");
// or...
Hashtable employee = _getEmployeeData(...);
DictionaryData moreData = new DictionaryData(employee)
DictionaryData
は非常に簡単で、単純なテストケースでは有用です。ただし、乱用しないよう十分に注意してください。すべてのアプリケーションにおいて、DataObject
の独自の実装を何度も記述し、使用することになります。特に、次のようなコードには十分注意してください。
// This is bad code; don't do this!
jdbc.sql.ResultSet jdbcResults = _getEmployee(...);
DictionaryData data = new DictionaryData();
data.put("empName", jdbcResults.getObject("empName"));
data.put("manager", jdbcResults.getObject("manager"));
data.put("ID", jdbcResults.getObject("ID"));
このようなコードの問題点は、オブジェクト間で結果をコピーするために、時間とメモリーの両方が無駄に使用されることです。必要時にのみデータを取得するDataObject
のカスタムの実装を使用する方が適切です。DictionaryData
をまったく使用しないという意味ではありません。1つか2つのデータをページに追加するだけの場合には、適切な方法です。それより複雑な場合、DictionaryData
は使用しないでください。
次に、独自のDataObject
クラスの記述方法を説明します。
このクラスでは、JavaのResourceBundle
をDataObject
に変換します。このクラスは大変便利なため、UIX Componentsに含まれています。ここではその説明を通して、DataObject
を実装する際の基本的な考え方を示します。この例では、DataObject
で例外を処理する方法も示します。
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import oracle.cabo.ui.data.DataObject;
public class BundleDataObject implements DataObject
{
public BundleDataObject(ResourceBundle bundle)
{
_bundle = bundle;
}
public Object selectValue(RenderingContext context, Object select)
{
try
{
return _bundle.getObject(select.toString());
}
catch (MissingResourceException e)
{
context.getErrorLog().logError(e);
return null;
}
}
private ResourceBundle _bundle;
}
留意点:
ResourceBundle
をラップした場合、1つのオブジェクトしか割り当てられません。しかし、DictionaryData
を作成してすべてのデータをResourceBundle
から取り出した場合、さらに多数のオブジェクトを作成する必要があります。また、前述の例の場合は、実行時に実際に使用されているキーのみが取得されます。
DataObject
で、例外がスローされないようにする必要があります。ここでは、MissingResourceException
を検出し、標準のUIX ErrorLog
に記録してから、安全な値すなわちnullが返されています。
DataObject
の独自の実装は、非常に簡単に記述できます。カスタムの実装を使用することによって、アプリケーションの効率やパフォーマンスが向上します。
DataObject
の作成後、RenderingContext
インタフェースに連結して、UIX Componentsのページで使用できるようにします。(前述のように、このインタフェースが、UIX Components BeanとuiXMLのページに、レンダリングに必要なコンテキストを渡します)。ここで、RenderingContext
の特定のメソッドに注目します。
public DataObject getDataObject(String namespaceURI,
String localName)
このメソッドによって、UIX Components BeanまたはBoundValue
では、任意の数のDataObject
へのアクセスが可能になります。UIXでは通常、これらのDataObject
は2つの文字列で識別されます。WebサイトのURLに基づく1つ以上のネームスペースと、他のコードと競合しない任意のローカル名を使用します。
ここで、DataObject
をRenderingContext
に渡す方法からは一度離れ、DataObject
からデータを取得してUINode
またはuiXMLに渡す方法を説明します。ここで、DataBoundValue
クラスや<dataObject>
要素が渡されます。
uiXMLでは、<dataObject>
要素を使用して、RenderingContext
のDataObject
を取得できます。この要素は、<contextProperty>
のように<boundAttribute>
要素の内部で使用できます。次の例は、前に示したものと同じuiXMLの例ですが、DataObject
を使用している点のみが異なります。
<link text="Static link text">
<boundAttribute name="destination">
<dataObject xmlns:myNS="http://www.example.org/"
source="myNS:dataObjName"
select="url"/>
</boundAttribute>
</link>
留意点:
<dataObject>
要素を使用しています。
DataObject
を指定しています。コロンの前の部分でネームスペースを、後の部分で名前を指定します。ここでは、ネームスペースとしてhttp://www.example.org、名前としてdataObjNameを使用しています。
DataObject.selectValue()
に渡す値を指定しています。
したがって、このuiXMLは、レンダリング時に次のJavaコードを実行していることと同じです。
// ...
DataObject dataObject = context.getDataObject("http://www.example.org",
"dataObjName");
Object destination = dataObject.selectValue("url");
// ...
次に、<boundAttribute>
と<dataObject>
を一緒に使用するための簡略フォームについて説明します。このフォームにより、このような一般的な例を簡単に入力できるようになります。
UIX Componentsでは、DataBoundValue
クラスによってこの機能が提供されます。
LinkBean bean = new LinkBean();
DataBoundValue destinationBinding =
new DataBoundValue(_EXAMPLE_NAMESPACE,
"dataObjName",
"url");
bean.setDestinationBinding(destinationBinding);
// ...
static private final String _EXAMPLE_NAMESPACE =
"http://www.example.org";
DataBoundValue
が中心的に使用されるため、DataBoundValue
を作成する次のような便利なメソッドがBeanに用意されています。
LinkBean bean = new LinkBean();
bean.setDestinationBinding(_EXAMPLE_NAMESPACE
"dataObjName",
"url");
ここまでで、独自のDataObject
を記述する方法、それらをRenderingContext
から取得する方法、およびそれらを属性にバインドする方法を学びました。この他に説明が必要なものは、DataObject
をRenderingContext
に渡す方法です。この方法では別のインタフェース、DataProvider
インタフェースを使用します。これは小規模なインタフェースです。
public interface DataProvider
{
public DataObject getDataObject(
RenderingContext context,
String namespace,
String name);
// ... methods omitted
}
まだ説明していないメソッドがいくつかありますが、中でもgetDataObject
は重要なメソッドです。これはDataObject
を取得するためにRenderingContext
でコールするメソッドです。このメソッドにはネームスペースと名前が渡されるため、各DataProvider
では様々な多くのDataObject
を提供できます。最後に、DataProvider
をRenderingContext
に連結する方法です。これは、もう1つのメソッドを使用するだけで可能です。
public interface RenderingContext
{
// ...
public void addDataProvider(DataProvider provider);
// ...
}
DataProvider
をRenderingContext
にする回数で何度でもこのメソッドをコールできます(実際には、すべてのDataProvider
をTableDataProvider
の中に入れ、それをCachingDataProvider
の中に入れる方が適切です。ただし、この方法については後で説明します)。これで準備ができました。次の要約の後、全工程を示す例に進みます。図4-1を参照してください。
図4-1: DataObject、DataProvider、RenderingContextおよびUINodeの関係
DataProvider
はDataObject
のコレクションです。DataObject
は任意のデータのコレクションです。RenderingContext
は、DataProvider
からDataObject
を取得します。DataBoundValue
オブジェクト(またはuiXMLのdataObject
要素)により、すべてがUINode属性に連結されます。ここでは、いくつかの例を示します。まず、UIX Componentsの例で、ビルトインのDataProvider
実装を紹介します。次に、uiXMLの例で、データ・バインドの設定に使用するuiXMLの要素をいくつか紹介します。
非常に単純なページを作成します。リンクが1つだけあり、コンテンツを1つのDataObject
にデータ・バインドします。すべてをJSPで表示します。最初にいくつかの定数を定義します。
public class DataDemo
{
// ...
private static final String _DEMO_NAMESPACE = "http://www.example.org/";
private static final String _DATA_OBJECT_NAME = "TextData";
private static final Object _TEXT_KEY = "textKey";
private static final Object _DESTINATION_KEY = "urlKey";
}
ここで、UIX Componentsのノードを作成する関数を記述します。
public class DataDemo
{
static public UINode getPage()
{
// An ultra-simple example - we'll create a single link:
LinkBean link = new LinkBean();
link.setTextBinding(
new DataBoundValue(_DEMO_NAMESPACE,
_DATA_OBJECT_NAME,
_TEXT_KEY)
);
// Or, we can use the built-in DataBoundValue convenience methods
link.setDestinationBinding(_DEMO_NAMESPACE,
_DATA_OBJECT_NAME,
_DESTINATION_KEY);
// And put the link inside of a "BodyBean" (see below)
BodyBean body = new BodyBean();
body.addIndexedChild(link);
return body;
}
// ...
}
このコードは、前に作成したコードによく似ています。リンクのBeanを作成し、2つの属性をデータ・オブジェクトにバインドしています。新たに追加したのはBodyBean
のみです。これはデータ・バインドの一部ではありません。HTMLの<body>
タグの作成に常に使用されるUIX Components Beanです。
ここで、DataProviderを設定する関数を記述します。
注意: これは非常に基本的な例です。データがハードコードされており、基本のDictionaryData
クラスを使用してそのデータを格納しています。ただし、レンダリング時にJSPのPageContext
を渡すことができます。つまり、そのコンテキストを使用してここで必要なすべての状態を取得できます。さらに、DataProvider
およびDataObject
にデータが要求される際、RenderingContext
はその両方に渡されます。また、ServletRequest
やHttpSession
などの一般的なサーブレット・オブジェクトをRenderingContextから取得できるため、すべてのデータを事前にロードしておく必要はありません。データが実際に要求されるまで待機できます。
public class DataDemo
{
// ...
static public DataProvider getDataProvider()
{
DataObject data = _getData();
// And put it in a DataProvider
TableDataProvider provider = new TableDataProvider();
provider.put(_DEMO_NAMESPACE, _DATA_OBJECT_NAME, data);
return provider;
}
static private DataObject _getData()
{
// Build up a DataObject
DictionaryData data = new DictionaryData();
data.put(_TEXT_KEY, "Shameless promotion!");
data.put(_DESTINATION_KEY, "http://www.oracle.com");
return data;
}
// ...
}
ここで使用したTableDataProvider
に注意してください。このクラスでは、DataObject
やその他のDataProvider
を、ネームスペースおよび名前によって分割します。
最後に、レンダリングを行うJSPを記述します。
<%@ page contentType="text/html" %>
<%@ page import='oracle.cabo.ui.ServletRenderingContext'%>
<%@ page import='oracle.cabo.ui.beans.StyleSheetBean'%>
<%@ page import='oracle.cabo.ui.data.DataProvider'%>
<%@ page import='yourpackage.DataDemo'%>
<html>
<head>
<%
// Create a rendering context
ServletRenderingContext rContext =
new ServletRenderingContext(pageContext);
// Include the stylesheet that UIX Components needs
StyleSheetBean.sharedInstance().render(rContext);
%>
</head>
<%
// Get the data provider, and attach it to the
// rendering context
DataProvider provider = DataDemo.getDataProvider();
rContext.addDataProvider(provider);
DataDemo.getPage().render(rContext);
%>
</html>
この例を実行すると、「Shameless promotion!」という語句が表示されます。これは、オラクル社のWebサイトにリンクされています。
この例では、別のBean、StyleSheetBean
も使用しています。このBeanでは、UIX Componentsのすべてのページで必要とされるスタイルシートを自動的に追加します。このBeanの使用による、1行のコードでの高性能処理やカスタマイズの実現については、後半のトピックで説明します。ここでは、このBeanがHTMLのすべての<head>
に属することを理解してください。
必要な作業はこれですべてです。1つの単純なリンクをレンダリングするには少々過度な処理です。ただし、データベースとの対話、ローカライズされたテキストの提供、またはローカライズされたデータに関するその他のソースの提供を可能にする、汎用のDataProvider
が使用されています。
ここで、uiXMLを使用して同じ例を作成します。必要なXMLを次に示します。
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:demo="http://www.example.org/">
<provider>
<data name="demo:linkData">
<method class="yourpackage.DataDemo" method="getLinkData"/>
</data>
</provider>
<contents>
<link>
<boundAttribute name="text">
<dataObject source="demo:linkData" select="textKey"/>
</boundAttribute>
<boundAttribute name="destination">
<dataObject source="demo:linkData" select="urlKey"/>
</boundAttribute>
</link>
</contents>
</dataScope>
例からわかるように、<boundAttribute>
要素によってコードが煩雑になっています。この例を簡潔にする簡略フォームについては後述します。ここでは、この例の新しい要素を見ていきます。
<dataScope>
: DataProvider
を追加できます。すべてのDataProvider
は<provider>
要素の内部に定義され、それらのプロバイダを使用できるすべてのUIは、<contents>
要素の内部に定義されます。
<data name="...">
<data>
要素では、DataObject
によって提供されるデータのネームスペースと名前を定義します。その内部には、データの取得方法を指定する1つの子要素を追加します。各DataObjectについて必ずしも1つの<data>
を指定する必要はありません。<data>
には、ローカル名としてワイルドカードのアスタリスク(name="demo:*"
など)を指定できます。
<method class="..." method="..."/>
<method>
で、データを取得する1つの方法を指定しています。このケースでは、イントロスペクションを使用してJavaメソッドからデータを取得します。<method>
要素が機能するためには、Javaメソッドを次のように指定する必要があります。
public class YourClassName
{
static public DataObject yourMethodName(
RenderingContext context, String namespace, String name)
{
...
}
}
ここで、このuiXMLでコールするJavaメソッドを記述します。DataDemo
の例に戻ります。
public class DataDemo
{
static public DataObject getLinkData(
RenderingContext context, String namespace, String name)
{
return _getData();
}
}
これで終了です。次に、データ・バインドのための簡略フォームを紹介します。これにより、DataObject
へのバインドを非常に簡単に行えるようになります。
DataObject
へのバインドは頻繁に行われるため、<boundAttribute>
を使用するよりはるかに簡潔な特殊構文をuiXMLに追加しました。前に示したコード例を次に示します。
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:demo="http://www.example.org/">
<provider>
...
</provider>
<contents>
<link>
<boundAttribute name="text">
<dataObject source="demo:linkData" select="textKey"/>
</boundAttribute>
<boundAttribute name="destination">
<dataObject source="demo:linkData" select="urlKey"/>
</boundAttribute>
</link>
</contents>
</dataScope>
次に、簡潔な構文を示します。
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui"
xmlns:demo="http://www.example.org/">
<provider>
...
</provider>
<contents>
<link data:text="textKey@demo:linkData"
data:destination="urlKey@demo:linkData"/>
</contents>
</dataScope>
このように簡潔になりました。変更点は次のとおりです。
<dataScope>
要素のdataに定義され、UIX Componentsのネームスペースが指定されています。すべてのネームスペース宣言と同様に、この宣言も任意の要素に定義できます。通常は、最初の要素に宣言を定義するのが最も簡単です。
<boundAttribute>
要素は2つともなくなりました。
DataObject
の選択値として、textKeyを使用するよう指定されています。
これと同じパターンを使用して、任意の属性を任意のDataObject
にバインドできます。
"data:attributeName=key@namespace:name".
文字列の連結、またはRenderingContext
プロパティへのバインドなどのような、複雑なことはできません。その場合は、<boundAttribute>
を使用してください。
ただし、この簡略フォームにはいくつかの種類があります(詳細は「uiXMLでの複雑なデータ・バインド」を参照してください)。keyは省略できます(アットマーク(@)は省略不可)。省略した場合、uiXMLではselectValue(...)
をコールするのではなく、DataObject
自体を属性として使用します。反対に、キーのみを指定することもできます。その構文の意味を、次のセクションで説明します。
ここまでで、BoundValue
とDataObject
を使用して、動的データを含むページを設定する方法を学びました。ただし、DataObject
インタフェースでは、一連のプロパティがサポートされるだけです。表形式のデータ、またはJava配列のようなその他のデータを表示する場合、これは非常に不便なインタフェースです。そのような場合に、DataObjectList
インタフェースが使用されます。
このトピックで説明する最後の新規インタフェースは、単純なインタフェースです。
public interface DataObjectList
{
public int getLength();
public DataObject getItem(int index);
}
DataObjectList
は、実際にはDataObject
配列です(実際には配列を使用しないため、DataObjectList
を不変に保つことができます。何かを設定するメソッドはないため、DataObject
を作成するか、DataObject
インスタンスを再利用することになります)。
ArrayDataSet
クラスは、DataObjectList
の単純で便利な実装です。DictionaryData
のように使用方法が単純ですが、すべてのDataObject
を事前に作成する必要があります。
DataObject[] array = new DataObject[10];
for (int i = 0; i < 10; i++)
{
array[i] = ...;
}
ArrayDataSet list = new ArrayDataSet(array);
DataObjectList
の独自の実装を記述する必要があることを覚えておいてください。
ここで、データをDataObjectList
から取り出して、ページに戻す方法について説明します。それには、現在のDataObject
を指定することが必要です。
すべてのデータ・フレームワークで、データの反復処理がサポートされています。これはJavaではforループに相当します。データベースではカーソルに相当します。UIX Componentsでは、現在のDataObject
の指定がそれに当たります。
このトピックで前述したRenderingContext.getDataObject
メソッドを思い出してください。これまで触れていませんが、DataObject
を取得するためのメソッドがもう1つあります。
public interface RenderingContext
{
// ..
/**
* Get a DataObject by namespace and name.
*/
public DataObject getDataObject(String namespaceURI,
String localName)
/**
* Get the "current" DataObject.
*/
public DataObject getCurrentDataObject();
// ..
}
この新しいメソッドgetCurrentDataObject()
は、現在のDataObject
を返します。これは、データベース・カーソルに相当するUIX Componentsのメソッドであり、DataObjectList
へのバインドに使用します。
Javaで現在のDataObject
からデータを取得するには、1つの引数を使用するDataBoundValue
の特別なコンストラクタ、または1つの引数を使用するBeanの便利なメソッドを使用します。
StyledTextBean textBean = new StyledTextBean();
textBean.setAttributeValue(UIConstants.TEXT_ATTR,
new DataBoundValue(TEXT_KEY));
// ... OR, EASIER ...
textBean.setTextBinding(TEXT_KEY);
uiXMLでは、次のソースをまとめて省略できます。
<styledText>
<boundAttribute name="text">
<dataObject select="textKey"/>
</boundAttribute>
</styledText>
<!-- OR -->
<!-- Note that there's no "@" sign here -->
<styledText data:text="textKey"/>
ここまでの内容をすべて使用して、TableBean
のためのDataObjectList
を作成してみましょう。
public class DataDemo
{
// ...
static private DataObjectList _getDataForTable()
{
DataObject[] rows = new DataObject[5];
for (int i = 0; i < rows.length; i++)
{
DictionaryData row = new DictionaryData();
row.put(_TEXT_KEY, "Row " + i);
row.put(_TEXT_2_KEY, "Column 2, row " + i);
rows[i] = row;
}
return new ArrayDataSet(rows);
}
// ...
private static final Object _TEXT_2_KEY = "text2Key";
}
ここでも、例を単純にするためにハードコードされたデータを使用しましたが、実際のアプリケーションではより多くのデータを処理できます。ここで、このDataObjectList
を表に入れる必要があります。次のようにコールできます。
TableBean table = new TableBean();
table.setTableData(_getDataForTable());
ただし、このように設定されたデータは動的にならないため、リクエストごとにTableBean
を再利用することはできません。データを動的にするために、前のデモで使用したものと同じDataObject
にデータを追加できます。新しいキーも必要になります。また、コードを変更して、TableBean
をページに追加します。
public class DataDemo
{
// ...
static public UINode getPage()
{
// ... old code ...
// And now, let's create the table
TableBean table = new TableBean();
table.setTableDataBinding(_DEMO_NAMESPACE,
_DATA_OBJECT_NAME,
_TABLE_DATA_KEY);
body.addIndexedChild(table);
return body;
}
static private DataObject _getData()
{
// Build up a DataObject
DictionaryData data = new DictionaryData();
// ... old code ...
// And now, add the DataObjectList
data.put(_TABLE_DATA_KEY, _getDataForTable());
return data;
}
// ...
static private final Object _TABLE_DATA_KEY = "tableKey";
}
前に示した例のように、DataProvider
を使用して、DataObject
がRenderingContext
に追加されます。このコードを変更する必要はありません。また、表データのバインドに以前と同じコードを使用していることに注意してください。tableDataは単に別の属性であり、その他の要素は変わっていません。
ここには多数のオブジェクトがあります。作成したオブジェクトについて見なおします。
DataProvider
は1つのDataObject
を提供します。
DataObject
には、2つのテキストと1つのDataObjectList
が含まれます。
DataObjectList
には、5つのDataObject
が含まれます。
DataObject
には2つのテキストが含まれます。
現在のDataObject
の指定が機能している例はまだ示していませんが、表に列を追加した後で、現在のDataObject
の指定を使用する必要が生じます。TableBean
の各列は、索引付けされた子によって表されます。addIndexedChild()
を3回コールすると、表に3つの列が作成されます。あるいは、uiXMLでは、<contents>
内部の各要素が1つの列に対応します。これらの各列は、行ごとに子要素をスタンプとして一度使用することによってレンダリングされます。
異なる方法でレンダリングされる各要素を行ごとに取得する点が特長です。これは、現在のDataObject
の指定を使用することで可能になります。表で最初の行をレンダリングする際、RenderingContext.getCurrentDataObject()
により、tableDataのDataObjectList
の最初のDataObject
が返されます。2行目のレンダリング時には、getCurrentDataObject()
は2番目のDataObject
を返します。以下同じ処理が繰り返されます。
ここで表に2つの列を追加します。1つは通常のテキスト列、もう1つは赤色の列です(この例では、StyleSheetBean
で提供されるスタイルの1つである、ビルトインのOraErrorText CSSスタイルを使用しています)。
public class DataDemo
{
// ...
static public UINode getPage()
{
// ... old code ...
// And now, let's create the table
TableBean table = new TableBean();
table.setTableDataBinding(...);
// Create the first column
StyledTextBean firstColumn = new StyledTextBean();
// Use _TEXT_KEY for the data of the first column
firstColumn.setTextBinding(_TEXT_KEY);
// Add it to the table
table.addIndexedChild(firstColumn);
// Create the second column, using _TEXT_2_KEY
StyledTextBean secondColumn = new StyledTextBean();
secondColumn.setStyleClass("OraErrorText");
secondColumn.setTextBinding(_TEXT_2_KEY);
table.addIndexedChild(secondColumn);
// ...
}
// ...
}
または、uiXMLでは次のようになります。
<table data:tableData="tableKey@demo:linkData">
<contents>
<styledText data:text="textKey"/>
<styledText styleClass="OraErrorText" data:text="text2Key"/>
</contents>
</table>
これで終了です。ここで、このレンダリング方法について説明します。表では、外枠や背景の設定など多くの処理が実行されます。その後で最初のセルがレンダリングされます。
行0、列0については、表は最初のStyledTextBean
を使用します。RenderingContext.getCurrentDataObject()
によって、DataObjectList
の最初のDataObject
が返されます。これには、「Row 0」および「Column 2, row 0」のエントリがあります。StyledTextBean
により、テキストであるDataBoundValue
が要求されます。現在のDataObject
が取得され、_TEXT_KEY
が要求されます。_TEXT_KEY
は「Row 0」を返し、そのセルにレンダリングされます。
次に、行0、列1が処理されます。同じ、現在指定されているDataObject
が有効ですが、もう1つのStyledTextBean
がレンダリングを行います。これは_TEXT_2_KEY
を要求し、「Column 2, row 0」をレンダリングします。
次は行1です。最初のStyledTextBean
に戻りますが、ここではすでにDataObjectList
の次のDataObject
に移動しています。そのため、RenderingContext.getCurrentDataObject()
は異なるDataObject
を返します。この行の最初の列には「Row 1」、2番目の列には「Column 2, row 1」が入ります。
表全体についてこの処理が繰り返されます。これは単純な例です。列ヘッダーや行ヘッダー、あるいは表で実行可能な多数の処理は追加していません。また、編集不可の普通のテキストのみを使用しています。ただし、これらはすべて同じ方法で機能します。表の行ごとにレンダリング方法を変える場合、現在指定されているDataObject
に、その変更内容を示す情報が指定されている必要があります。
たとえば、各行にリンクを指定し、それぞれの宛先が異なるとします。この場合は簡単です。LinkBean
または<link>
要素を使用してdestination属性を現在指定されているDataObject
にデータ・バインドし、各行の宛先を含むようにDataObjectList
を更新します。UIX Componentsでは、すべてについてデータ・バインドが可能なため、各行が異なるようにできます。
uiXML内にDataObject
とDataObjectList
の両方を直接定義できます。ページが実際のデータソースに連結される前にダミー・データを作成できるため、非常に便利です。また、一部のBeanでDataObject
を直接使用する場合にも有用です。たとえば、<tree>
ではデータ・モデルとしてDataObject
を使用します。
まず、DataProvider
の新しい要素、<inline>
を紹介します。
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:demo="http://www.example.org/">
<provider>
<data name="demo:linkData">
<inline>
.... data object is in here ...
</inline>
</data>
</provider>
<contents>
...
</contents>
</dataScope>
この要素は、前述した<method>
要素に似た動作をしますが、Javaコードはコールしません。uiXML内でデータを直接定義します。
<inline>
のすべての属性によって、作成されるDataObject
内にキーと値のペアが定義されます。次に例を示します。
<inline url="http://example" text="Inline text">
</inline>
上の例では、2つの値を持つDataObject
を定義しています。1つのキーはurl、もう1つのキーはtextです。簡単に定義できます。
ただし、子要素を使用し、サブ値としてDataObject
およびDataObjectList
を追加することもできます。要素の名前は、子のDataObject
またはDataObjectList
が格納されるキーです。同じ要素名が複数ある場合は、それらの要素がまとまってDataObjectList
を定義します。1つしかない場合、DataObject
と単一要素のDataObjectList
の両方が定義されます。前述のように、これらは単なるインタフェースです。1つのJavaオブジェクトで両方を実装できます。次の例でわかりやすく示します。
<inline foo="Inline text">
<stuff random="Stuff text"/>
<row text="First row"/>
<row text="Second row"/>
</inline>
この例には、3つのオブジェクトを含むDataObject
があります。
Inline Text
。
DataObject
。キーrandomのテキストStuff textを含みます。ただし、これは単一要素のDataObjectList
としても使用されます。
DataObjectList
。それぞれ1つのテキストを含む2つのDataObject
を含みます。
<dataScope>
<provider>
<data name="demo:inlineData">
<inline>
<tableKey textKey="Row 0" text2Key="Column 2, Row 0"/>
<tableKey textKey="Row 1" text2Key="Column 2, Row 1"/>
... etc ...
<tableKey textKey="Row 4" text2Key="Column 2, Row 4"/>
</inline>
</data>
</provider>
<contents>
<table data:tableData="tableKey@demo:inlineData">
<contents>
<styledText data:text="textKey"/>
<styledText styleClass="OraErrorText" data:text="text2Key"/>
</contents>
</table>
</contents>
</dataScope>
「DataObjectとuiXML」のセクションでは、データ・バインドの簡略フォーム、つまりdata:attributeName="key@name"
について学びました。ここで、key
はテキスト・キーであり、name
はDataObject
を参照しています(name
はnamespace:localname
という形式で指定)。このセクションでは、キーとデータ・オブジェクトをネストして、さらに複雑なデータ・バインドを生成する方法を説明します。最初に、次のフォームを使用して、ネストされたキー・データ・バインドを生成します。
data:attributeName="keyN@...@key2@key1@name"
この場合、この属性の値を計算する際に、name
で参照されるDataObject
についてkey1
が使用され、別のDataObject
が生成されます。2番目のDataObject
にはkey2
が使用され、3番目のDataObject
が生成されます。このプロセスは、keyN
が使用され、この属性の最終値が生成されるまで続きます。すべてのDataObject
の値自体がDataObject
であることが必要です。最後のキーkeyN
の値のみは、(属性が必要とするタイプであれば)DataObject
でなくてもかまいません。ネストされたキー・バインドの例を次に示します。
<dataScope>
<provider>
<data name="families">
<inline>
<Smith members="4">
<address number="2255" street="37th Ave" city="San Francisco"
state="CA" zip="94116" />
</Smith>
<Jones members="3">
<address number="500" street="Oracle Parkway" city="Redwood Shores"
state="CA" zip="94065" />
</Jones>
</inline>
</data>
</provider>
<contents>
<messageTextInput prompt="The Smiths live in"
data:text="city@address@Smith@families" /> <!--San Francisco-->
<messageTextInput prompt="The Jones's live in"
data:text="city@address@Jones@families" /> <!--Redwood Shores-->
</contents>
</dataScope>
上の例では、最初のmessageTextInput
で「The Smiths live in San Francisco」が生成され、2番目で「The Jones's live in Redwood Shores」が生成されます。
ネストされたデータ・オブジェクト・バインドを生成するためにカッコも使用できます。次の例について考えてみます。
data:attributeName="(key1@name1)@name2"
上の例では、name1
(で参照されるDataObject
)でkey1
が使用されてキーを生成し、そのキーがname2
で使用されてこの属性の最終値を生成しています。これは、キー自体がデータ・バインドされる例です。データ・オブジェクトの一部をデータ・バインドすることもできます。次の2つの例は同じ意味です。
<!-- These two are equivalent -->
data:attributeName="key2@(key1@name)"
data:attributeName="key2@key1@name"
次に示すのは、前の例で作成されたfamilies
データ構造を使用したカッコの例です。これによって、「The Jones family has 3 members.」が生成されます。
<dataScope>
<provider>
<data name="families">
... as above ...
</data>
<data name="selection">
<inline current="Jones" />
</data>
</provider>
<contents>
The<link data:text="current@selection"/> family
has<link data:text="members@(current@selection)@families" />
members.
</contents>
</dataScope>
カッコは、次の例のようにネストすることもできます。
data:attributeName="((key1@name1)@name2)@name3"
この例では、key1
がname1
で使用されてキーを生成し、そのキーがname2
で使用され、最終値を計算するname3
に対する別のキーを生成します。
アットマーク(@)の前後のテキストはオプションです。キーを省略すると、次の例のようにDataObject
自体が返されます。
<!-- The following attribute is bound to the data object itself -->
data:attributeName="@name"
データ・オブジェクト名の一部を省略すると、次の例のように、現在のデータ・オブジェクトでキーが使用されます(アットマーク(@)が指定されない場合のデフォルト)。
<!-- These keys are used with the current data object -->
data:attributeName="key@"
data:attributeName="key"
アットマーク(@)が指定されない場合、暗黙的にアットマーク(@)があるものと仮定されます(上の例の2番目のバインドの場合)。次の例で、この詳細を示します。
<!-- These are different bindings -->
data:attributeName="key@name"
data:attributeName="(key@name)"
上の例の2つのバインドは同じではありません。2番目のバインドには暗黙のアットマーク(@)があり、data:attributeName="(key@name)@"
と記述することもできます。2番目のバインドでは、key
をデータ・オブジェクトname
に適用し返される値が、現在のデータ・オブジェクトのキーとして使用されます。
キーおよびデータ・オブジェクト名には一定の制限があります。たとえば、キーのテキストにはアットマーク(@)を使用できません。uiXMLの将来のバージョンでは、このような文字のエスケープが可能になり、使用できるようになる予定です。
DataObject
とDataObjectList
は非常に柔軟ですが、多くの開発者はJavaBeansによる開発に慣れています。いつでも使用できる、記述済の多数のJavaBeansを持っている場合もあるでしょう。このような資産をUIXの使用時にあきらめる必要はありません。UIXはデフォルトでJavaBeansをサポートしているため、コード行を記述する必要はほとんどないためです。
JavaBeansを使用して、最初の例を書き直してみましょう。まず最初に、Java側を書き直します。
public class DataDemo
{
static public Object getLinkBean(
RenderingContext context,
String namespace,
String name)
{
return new LinkDataBean("http://www.oracle.com",
"Shameless bean promotion!");
}
}
public class LinkDataBean
{
public LinkDataBean(String url, String text)
{
_url = url;
_text = text;
}
public String getUrl()
{
return _url;
}
public String getText()
{
return _text;
}
private String _url;
private String _text;
}
この例で興味深いのはいくつかの点のみです。新規のgetLinkBean()
メソッドを記述しましたが、これはDataObject
を返しません。<method>
要素では、使用するメソッドがDataObject
を返す必要があると言われていたことを思い出してください。これは今や、必須ではありません(以前は必須でした)。使用するメソッドはどのオブジェクトを返してもよく、そのオブジェクトをDataObject
に変換する処理が最大限に機能します。また、LinkDataBean
には引数を持たないコンストラクタがないため、これは技術的にもJavaBeansではないことに気付いたかもしれません。(Beansそのものを作成する必要はないので、これは無視してもかまいません。)完全なJavaBeansもサポートされていますが、それよりもはるかに柔軟性を持っているのです。すぐに詳しく説明しますが、その前にXMLの例を見てみましょう。
<dataScope xmlns="http://xmlns.oracle.com/uix/ui"
xmlns:data="http://xmlns.oracle.com/uix/ui"
xmlns:demo="http://www.example.org/">
<provider>
<data name="demo:linkData">
<method class="yourpackage.DataDemo" method="getLinkBean"/>
</data>
</provider>
<contents>
<link data:text="text@demo:linkData"
data:destination="url@demo:linkData"/>
</contents>
</dataScope>
変更点はほとんどありません。<method>
要素はgetLinkBean()
メソッドを参照するようになりました。キーとしてtextKeyおよびurlKeyを使用するかわりに、textおよびurlに変更しました。このため、BeanメソッドをgetUrlKey()
およびgetTextKey()
と指定する必要がなくなりました。DataObject
を参照する1コード行は、もういらなくなりました。
前述したように、使用するクラスは完全なJavaBeansである必要はありませんが、完全な方がより好ましい状態です。次のような状況はすべて自動的に処理されます。
LinkDataBean
を次のように記述することも可能です。
public class LinkDataBean
{
public LinkDataBean(String url, String text)
{
this.url = url;
this.text = text;
}
public String url;
public String text;
}
これは通常、独自のJavaBeansでは良い設計と言えませんが、特別なアダプタがなくてもjava.awt.Point
のようなレガシー・クラスをサポートできることを意味しています。
// The interface is public...
public interface LinkData
{
public String getText();
public String getUrl();
}
// ...but the bean is private
class LinkDataBean implements LinkData
{
...
}
最後に、java.util.Map
を実装するオブジェクトにもすべて自動的に適応します。JDK 1.2以上ではjava.util.Hashtable
クラスはMap
を実装するため、ユーザーはHashtables
を返すことが可能で、それらは自動的にDataObject
へラップされます。
UIXでは、DataObjectList
の処理も単純化されています。オブジェクト配列およびjava.util.List
の双方とも、自動的にDataObjectList
に適合されます。(JDK 1.2でHashtable
がMap
を実装するように、Vector
もList
を実装するため、そのクラスも同様にサポートされます。)
配列およびList
はDataObject
を含む必要はありませんが、それは可能です。かわりに、JavaBeans、Map
またはDataObject
を含むこともできます。特に秩序立てて考えない場合は、いずれか1つが3つすべてを含むことも可能です。
JavaBeans、配列およびその他に対するUIXサポートは、すべて再帰的です。これまでに学んだ複雑なデータ・バインド構文は、DataObject
を返すDataObject
に適用されたように、他のJavaBeansを返すJavaBeansにも同じように適用されます。
このように簡単な方法があるのならば、なぜDataObject
およびDataObjectList
の説明に長い時間をかけてきたのでしょうか。DataObject
はUIXでデータ用に使用される実際の概念です。第一に、Java APIを使用してBeansを作成する場合、メソッドの取得対象であるDataObject
を使用する必要があります。(いくつかのパラグラフで説明されるように、依然としてBeanAdapterUtils
を使用して手動でJavaBeansをDataObject
に変換することもできます。)
DataObject
はJavaBeansよりはるかに柔軟でもあります。JavaBeansでは、キーの完全セットをコンパイル時に知っておく必要があり、そのキーはすべて有効なメソッド名である必要があります。つまり、実行時に動的に状態が変化するBC4JまたはJDBCの行に対してバインドする単一のJavaBeansを記述することは不可能ですが、DataObject
を使用すれば簡単です。このため、JavaBeansを使用してすべてのデータを記述することも可能ですが、そうしない可能性があります。DataObject
の使用方法を知らなくても全アプリケーションを記述することはできますが、実際の動作を知っておいた方が賢明です。
また、これらのJavaBeansに対するビルトイン・サポートによるオーバーヘッドがまったくないわけではありません。パフォーマンス上のコストがかかります。最初に、DataObject
を実装するアダプタ・オブジェクトを作成する必要があります。これらは軽量であるとは言え、オブジェクト作成は可能ならば避けた方が無難です。次に、イントロスペクション(実行時におけるメソッドの動的な検出およびコール)は本質的に動作が遅くなります。このプロセスの最もコストが高い部分(Method
オブジェクトの検出)のキャッシュについては快適な動作が提供されますが、Method
オブジェクトへのコールについては依然として、手動コーディングされたDataObject
におけるコンパイル済メソッド・コールよりも動作が遅くなります。
ただし、「早まった最適化は諸悪の根源である(Premature optimization is the root of all evil)」というプログラミングについての有名な格言を思い出してください。手動コーディングされたDataObject
がより速いとしても、DataObject
の記述に時間を費やすべきということにはなりません。適度に使用されていれば、JavaBeansの使用がパフォーマンスに重大な影響を与える理由はありません。本質的に動作が遅いJavaBeans(データベースにアクセスする必要がある場合など)については、アダプタの追加オーバーヘッドは少なくほとんど問題になりません。ただしプロファイリングを実行して、Beansの1つの適合オーバーヘッドがパフォーマンスに重大な影響を与えていると判断した場合は、オブジェクト作成およびイントロスペクション・オーバーヘッドの両方の問題に取り組むことができます。
まずは、必要になるたびにアダプタ・オブジェクトを作成することを避けます。UIXで自動的にアダプタを作成するのではなく、手動で作成してその結果をキャッシュします。BeanAdapterUtils.getAdapter()
を使用すると手動でアダプタを作成できます。次に例を示します。
public class DataDemo
{
static public Object getLinkBean(
RenderingContext context,
String namespace,
String name)
{
return _sAdapter;
}
static private LinkDataBean _sInstance =
new LinkDataBean("http://www.oracle.com",
"Shameless bean promotion!");
// Create a static adapter:
static private DataObject _sAdapter;
static
{
try
{
_sAdapter = BeanAdapterUtils.getAdapter(_sInstance);
}
catch (InstantiationException ie) { }
catch (IllegalAccessException iae) { }
}
}
これは、Beanの存続期間が長い場合のみ有効です。Beanが1つのリクエストのみで使用されている場合、アダプタのキャッシュはそれほど有効ではありません。ただしそれがセッション・レベルまたはアプリケーション・レベルのBeanの場合、これはちょっとしたことですが簡単なパフォーマンス向上につながります。
次に、独自のDataObject
アダプタを記述して、イントロスペクションの本質的なパフォーマンスの問題に取り組みます。もしくはより効果的な方法として、アダプタを自動的に記述できます。UIXには、コンパイル済JavaBeansを取得しDataObject
アダプタを自動的に記述する、BuildBeanDOAdapter
というJavaベースのツールが組み込まれています。コマンドラインで次のように入力します。
java oracle.cabo.ui.tools.BuildBeanDOAdapter yourpackage.LinkDataBean
ここで生成されるコードすべては列記しませんが、次に注目すべき部分を示します。selectValue()
コードが例のLinkDataBean
に対して生成されています。
public Object selectValue(RenderingContext context, Object select)
{
LinkDataBean instance = _instance;
if (instance == null)
return null;
try
{
if ("url".equals(select))
return instance.getUrl();
if ("text".equals(select))
return instance.getText();
}
catch (Exception e)
{
context.getErrorLog().logError(e);
}
return null;
}
これはイントロスペクションよりもはるかに速い動作です。最新のベンチマーク(Windows 2000上のJava 1.3.0)では、20から30倍速いとされています。ただし、数百ものプロパティがある大規模なJavaBeansでは、String.equals()
に対するこれらのコールは重大な問題となり、この最適化が実際にはパフォーマンスにとって有害となる可能性があります。これらのケースのため、アダプタ構築ツールは"-fast"コマンドライン・オプションをサポートしています。結果として生じたクラスはStringハッシュコードを効果的に使用して、selectValue()
のスピードを基本イントロスペクションよりも速いレベルまで再び引き上げます。どちらの方法でアダプタ・クラスを構築しても、これらのアダプタは、boolean
およびint
の戻り値をBoolean
およびInteger
のオブジェクトに変換するような一般的なイントロスペクションよりもはるかにスムーズでもあります。
これらのアダプタ・クラスを一度作成すると、データ・バインド・コードを変更してこれらのアダプタを明示的に作成できます。
public class DataDemo
{
static public Object getLinkBean(
RenderingContext context,
String namespace,
String name)
{
LinkDataBean bean = ...;
return new LinkDataBeanDataObject(bean);
}
}
ただし、ここまでのすべての手順を確実にこなしていくことを確認するのは冗長な(エラーも起こりやすい)作業です。代替案としてアダプタを、静的なregisterAdapter()
コールによってBeanAdapterUtils
に直接登録できます。このコールを初期化コードに追加すると、残りのコードは以前のようにBeanインスタンスを続けて返すことができます。
public class DataDemo
{
static public Object getLinkBean(
RenderingContext context,
String namespace,
String name)
{
// Under the covers, UIX will use LinkDataBeanDataObject to
// adapt this bean, but we don't to know that here!
return new LinkDataBean(...);
}
// Register the adapter once
static
{
LinkDataBeanDataObject.registerAdapter();
}
}