Teedaネスト対応

Teedaでネストしたプロパティー表示の実験

これで実験してから一年半ぐらい経過していますが、組んでみました。

	data3Dto = new Data3Dto();
	data3Dto.data5 = "DataText5";
	data3Dto.data6 = "DataText6";
	data3Dto.data2Dto = new Data2Dto();
	data3Dto.data2Dto.data3 = "DataText3";
	data3Dto.data2Dto.data4 = "DataText4";
	data3Dto.data2Dto.dataDto = new DataDto();
	data3Dto.data2Dto.dataDto.data1 = "DataText1";
	data3Dto.data2Dto.dataDto.data2 = "DataText2";

こんな感じのデータが

<span id="data3Dto_data5">data3Dto_data5</span><br />
<span id="data3Dto_data6">data3Dto_data6</span><br />
<span id="data3Dto_data2Dto_data3">data3Dto_data2Dto_data3</span><br />
<span id="data3Dto_data2Dto_data4">data3Dto_data2Dto_data4</span><br />
<span id="data3Dto_data2Dto_dataDto_data1">data3Dto_data2Dto_dataDto_data1</span><br />
<span id="data3Dto_data2Dto_dataDto_data2">data3Dto_data2Dto_dataDto_data2</span><br />
<span id="data3Dto_data2Dto_dataDto_data3">data3Dto_data2Dto_dataDto_data3</span><br />

こんな感じで利用できます。
最後のdata3Dto_data2Dto_dataDto_data3はプロパティーがないので、データが入らない状態ででます。標準だと例外エラーになるのでここのチェックが一番面倒だと思います。

以下パッチですが、

http://akira.info/labs/NestTeeda/teeda.patch
http://akira.info/labs/NestTeeda/teedaNest20110224.lzh

ここにパッチと、サンプルで動いているプロジェクト起きました。
Eclipseのパッチはなんかおかしい。。。ひとつだけ適応されないところがでてきています(涙)

もう少しテストを書く必要があるけれど、普通にデータ表示するだけだったらこれでいいのかな?
性能実験やっていないので、もう少し速度的な最適化はできるきがします。

Index: teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/TagProcessorAssembleImplTest.java
===================================================================
--- teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/TagProcessorAssembleImplTest.java	(revision 4307)
+++ teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/TagProcessorAssembleImplTest.java	(working copy)
@@ -450,6 +450,10 @@
             return false;
         }
 
+        public boolean hasNestProperty(String name) {
+            return false;
+        }
+
         public boolean isModified() {
             return false;
         }
Index: teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/page/AaaDto.java
===================================================================
--- teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/page/AaaDto.java	(revision 4307)
+++ teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/page/AaaDto.java	(working copy)
@@ -19,10 +19,11 @@
 
 /**
  * @author higa
- * 
+ *
  */
 
 public class AaaDto implements Serializable {
 
     public static final String COMPONENT = "instance=session";
+    public String aaaBbb;
 }
Index: teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/PageDescImplTest.java
===================================================================
--- teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/PageDescImplTest.java	(revision 4307)
+++ teeda-extension/src/test/java/org/seasar/teeda/extension/html/impl/PageDescImplTest.java	(working copy)
@@ -43,6 +43,15 @@
         assertFalse(pd.hasProperty(null));
     }
 
+    public void testHasNestProperty() throws Exception {
+        PageDesc pd = createPageDesc(FooPage.class, "fooPage");
+        assertFalse(pd.hasNestProperty("aaa"));
+        assertFalse(pd.hasNestProperty("aaaDto"));
+        assertTrue(pd.hasNestProperty("aaaDto_aaaBbb"));
+        assertFalse(pd.hasNestProperty(null));
+    }
+
+
     public void testHasItemsProperty() throws Exception {
         PageDesc pd = createPageDesc(FooPage.class, "fooPage");
         assertTrue(pd.hasItemsProperty("cccItems"));
Index: teeda-extension/src/main/java/org/seasar/teeda/extension/html/impl/PageDescImpl.java
===================================================================
--- teeda-extension/src/main/java/org/seasar/teeda/extension/html/impl/PageDescImpl.java	(revision 4307)
+++ teeda-extension/src/main/java/org/seasar/teeda/extension/html/impl/PageDescImpl.java	(working copy)
@@ -17,6 +17,7 @@
 
 import java.io.File;
 import java.io.Serializable;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
@@ -72,6 +73,8 @@
 
     private static final String[] EMPTY_SCOPES = new String[0];
 
+    private Class pageClass;
+
     public PageDescImpl(Class pageClass, String pageName) {
         this(pageClass, pageName, null);
     }
@@ -90,6 +93,8 @@
     }
 
     protected void setup(Class pageClass) {
+        this.pageClass = pageClass;
+
         BeanDesc beanDesc = BeanDescFactory.getBeanDesc(pageClass);
         for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
             PropertyDesc pd = beanDesc.getPropertyDesc(i);
@@ -172,6 +177,57 @@
         return propertyNames.contains(name);
     }
 
+    public boolean hasNestProperty(String name) {
+        if( name == null ){
+            return false;
+        }
+
+        BeanDesc beanDesc = BeanDescFactory.getBeanDesc(pageClass);
+        String[] items = name.split("_");
+
+        if( items.length < 2 ){
+            return false;
+        }
+
+        for (int i = 0; i < beanDesc.getPropertyDescSize(); ++i) {
+            PropertyDesc pd = beanDesc.getPropertyDesc(i);
+            String propertyName = pd.getPropertyName();
+            if( items[0].equals(propertyName) ){
+                String[] items2 = new String[items.length-1];
+                for( int j = 0 ; j < items.length-1; j++ ){
+                    items2[j] = items[j+1];
+                }
+                return hasNestPropertySub( items2, pd.getPropertyType() );
+            }
+
+        }
+
+        return false;
+    }
+
+    private boolean hasNestPropertySub(String[] items,Class propertyClass) {
+        Field propertyFields[] = propertyClass.getDeclaredFields();
+
+        for( int i = 0 ; i < propertyFields.length ; i++ ){
+            String fieldsName = propertyFields[i].getName();
+            if( items[0].equals(fieldsName) ){
+                if( items.length == 1 ){
+                    return true;
+                } else {
+                    String[] items2 = new String[items.length-1];
+                    for( int j = 0 ; j < items.length-1; j++ ){
+                        items2[j] = items[j+1];
+                    }
+                    Class fieldsClass = propertyFields[i].getType();
+
+                    return hasNestPropertySub( items2, fieldsClass );
+                }
+            }
+        }
+
+        return false;
+    }
+
     public boolean hasItemsProperty(String name) {
         return itemsPropertyNames.contains(name);
     }
Index: teeda-extension/src/main/java/org/seasar/teeda/extension/html/PageDesc.java
===================================================================
--- teeda-extension/src/main/java/org/seasar/teeda/extension/html/PageDesc.java	(revision 4307)
+++ teeda-extension/src/main/java/org/seasar/teeda/extension/html/PageDesc.java	(working copy)
@@ -24,6 +24,8 @@
 
     boolean hasProperty(String name);
 
+    boolean hasNestProperty(String name);
+
     /**
      * ForEach繧ТelectOneMenu縺ァ縺ョPage繧ッ繝ゥ繧ケ縺ォ謖√▽Collection縺後≠繧句?蜷医↓true繧定ソ斐☆.
      * @param name
Index: teeda-extension/src/main/java/org/seasar/teeda/extension/html/factory/OutputTextFactory.java
===================================================================
--- teeda-extension/src/main/java/org/seasar/teeda/extension/html/factory/OutputTextFactory.java	(revision 4307)
+++ teeda-extension/src/main/java/org/seasar/teeda/extension/html/factory/OutputTextFactory.java	(working copy)
@@ -67,6 +67,9 @@
         if (isLabel(id, elementNode)) {
             return true;
         }
+        if (isNest(id, pageDesc)) {
+            return true;
+        }
         return pageDesc.hasProperty(id);
     }
 
@@ -88,6 +91,11 @@
         if (pageDesc.hasProperty(id)) {
             properties.put(JsfConstants.VALUE_ATTR, getBindingExpression(
                     pageDesc.getPageName(), id));
+        } else if( isNest(id, pageDesc) ){
+            String[] items = id.split("_");
+            String itemName = implode( items, "." );
+            properties.put(JsfConstants.VALUE_ATTR, getBindingExpression(
+                    pageDesc.getPageName(), itemName));
         } else {
             final String key = toNormalizeId(id);
             TextNode firstTextNode = elementNode.getFirstTextNode();
@@ -96,6 +104,26 @@
         }
     }
 
+    private static String implode(Object[] array, String sep) {
+        if (array == null) {
+            return null;
+        } else if (array.length < 1) {
+            return "";
+        } else if (array.length < 2) {
+            return (array[0] != null) ? array[0].toString() : "";
+        }
+
+        StringBuffer buf = new StringBuffer(
+                (array[0] != null) ? array[0].toString() : "");
+
+        for (int i = 1; i < array.length; i++) {
+            buf.append(sep);
+            buf.append((array[i] != null) ? array[i].toString() : "");
+        }
+
+        return buf.toString();
+    }
+
     protected boolean isLabel(final String id, final ElementNode elementNode) {
         final String key = toNormalizeId(id);
         if (!TeedaExtensionConfiguration.getInstance().outputTextLabelUnderAnchorOnly) {
@@ -115,6 +143,20 @@
         }
     }
 
+    protected boolean isNest(final String id, PageDesc pageDesc) {
+        if( id == null ){
+            return false;
+        }
+
+        String[] items = id.split("_");
+
+        if( items.length < 2 ){
+            return false;
+        }
+
+        return pageDesc.hasNestProperty(id);
+    }
+
     protected String toNormalizeId(String id) {
         final int pos = id.lastIndexOf('-');
         if (pos >= 0) {