bug 399381: Bean-based table field data and name-based import/export of table data 
https://bugs.eclipse.org/bugs/show_bug.cgi?id=399381
diff --git a/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldBaseForm.java b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldBaseForm.java
new file mode 100644
index 0000000..becde4d
--- /dev/null
+++ b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldBaseForm.java
@@ -0,0 +1,71 @@
+/*******************************************************************************

+ * Copyright (c) 2010 BSI Business Systems Integration AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     BSI Business Systems Integration AG - initial API and implementation

+ ******************************************************************************/

+package formdata.client.ui.forms.replace;

+

+import org.eclipse.scout.commons.annotations.FormData;

+import org.eclipse.scout.commons.annotations.FormData.SdkCommand;

+import org.eclipse.scout.commons.annotations.Order;

+import org.eclipse.scout.commons.exception.ProcessingException;

+import org.eclipse.scout.rt.client.ui.basic.table.AbstractTable;

+import org.eclipse.scout.rt.client.ui.basic.table.ITable;

+import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractStringColumn;

+import org.eclipse.scout.rt.client.ui.form.AbstractForm;

+import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;

+import org.eclipse.scout.rt.client.ui.form.fields.tablefield.AbstractTableField;

+import org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldBeanData;

+

+import formdata.shared.services.process.replace.TableFieldBaseFormData;

+

+@FormData(value = TableFieldBaseFormData.class, sdkCommand = SdkCommand.CREATE)

+public class TableFieldBaseForm extends AbstractForm {

+

+  /**

+   * @throws ProcessingException

+   */

+  public TableFieldBaseForm() throws ProcessingException {

+    super();

+  }

+

+  @Order(10.0)

+  public class MainBox extends AbstractGroupBox {

+

+    @Order(10.0)

+    @FormData(sdkCommand = SdkCommand.USE, value = AbstractTableFieldBeanData.class)

+    public class TableField extends AbstractTableField<TableField.Table> {

+

+      public class Table extends AbstractTable {

+

+        @Order(10.0)

+        public class FirstColumn extends AbstractStringColumn {

+

+        }

+

+        @Order(20.0)

+        public class SecondColumn extends AbstractStringColumn {

+

+        }

+      }

+    }

+

+    @Order(20.0)

+    @FormData(sdkCommand = SdkCommand.USE, value = AbstractTableFieldBeanData.class)

+    public class EmptyTableField extends AbstractTableField<EmptyTableField.Table> {

+

+      public class Table extends AbstractTable {

+      }

+    }

+

+    @Order(30.0)

+    @FormData(sdkCommand = SdkCommand.USE, value = AbstractTableFieldBeanData.class)

+    public class NoTableField extends AbstractTableField<ITable> {

+    }

+  }

+}

diff --git a/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldExForm.java b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldExForm.java
new file mode 100644
index 0000000..efeebff
--- /dev/null
+++ b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.client/src/formdata/client/ui/forms/replace/TableFieldExForm.java
@@ -0,0 +1,85 @@
+/*******************************************************************************

+ * Copyright (c) 2010 BSI Business Systems Integration AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     BSI Business Systems Integration AG - initial API and implementation

+ ******************************************************************************/

+package formdata.client.ui.forms.replace;

+

+import org.eclipse.scout.commons.annotations.FormData;

+import org.eclipse.scout.commons.annotations.FormData.SdkCommand;

+import org.eclipse.scout.commons.annotations.Order;

+import org.eclipse.scout.commons.annotations.Replace;

+import org.eclipse.scout.commons.exception.ProcessingException;

+import org.eclipse.scout.rt.client.ui.basic.table.AbstractTable;

+import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractBooleanColumn;

+import org.eclipse.scout.rt.client.ui.basic.table.columns.AbstractStringColumn;

+

+import formdata.shared.services.process.replace.TableFieldExFormData;

+

+/**

+ *

+ */

+@FormData(value = TableFieldExFormData.class, sdkCommand = SdkCommand.CREATE)

+public class TableFieldExForm extends TableFieldBaseForm {

+

+  public TableFieldExForm() throws ProcessingException {

+    super();

+  }

+

+  @Replace

+  public class TableExtendedField extends TableFieldBaseForm.MainBox.TableField {

+

+    public TableExtendedField(TableFieldBaseForm.MainBox container) {

+      container.super();

+    }

+

+    public class TableEx extends Table {

+

+      @Order(30)

+      @Replace

+      public class FirstExtendedColumn extends FirstColumn {

+

+      }

+

+      @Order(40)

+      public class BooleanColumn extends AbstractBooleanColumn {

+

+      }

+    }

+  }

+

+  @Replace

+  public class EmptyTableExtendedField extends TableFieldBaseForm.MainBox.EmptyTableField {

+

+    public EmptyTableExtendedField(TableFieldBaseForm.MainBox container) {

+      container.super();

+    }

+

+    public class TableEx extends Table {

+

+      public class SingleColumn extends AbstractStringColumn {

+

+      }

+    }

+  }

+

+  @Replace

+  public class NoTableExtendedField extends TableFieldBaseForm.MainBox.NoTableField {

+

+    public NoTableExtendedField(TableFieldBaseForm.MainBox container) {

+      container.super();

+    }

+

+    public class Table extends AbstractTable {

+

+      public class NewColumn extends AbstractStringColumn {

+

+      }

+    }

+  }

+}

diff --git a/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldBaseFormData.java b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldBaseFormData.java
new file mode 100644
index 0000000..cd06bb8
--- /dev/null
+++ b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldBaseFormData.java
@@ -0,0 +1,158 @@
+package formdata.shared.services.process.replace;

+

+import org.eclipse.scout.rt.shared.data.basic.table.AbstractTableRowData;

+import org.eclipse.scout.rt.shared.data.form.AbstractFormData;

+import org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldBeanData;

+

+public class TableFieldBaseFormData extends AbstractFormData {

+  private static final long serialVersionUID = 1L;

+

+  public TableFieldBaseFormData() {

+  }

+

+  public EmptyTable getEmptyTable() {

+    return getFieldByClass(EmptyTable.class);

+  }

+

+  public NoTable getNoTable() {

+    return getFieldByClass(NoTable.class);

+  }

+

+  public Table getTable() {

+    return getFieldByClass(Table.class);

+  }

+

+  public static class EmptyTable extends AbstractTableFieldBeanData {

+    private static final long serialVersionUID = 1L;

+

+    public EmptyTable() {

+    }

+

+    @Override

+    public EmptyTableRowData addRow(int rowState) {

+      return (EmptyTableRowData) super.addRow(rowState);

+    }

+

+    @Override

+    public EmptyTableRowData addRow() {

+      return (EmptyTableRowData) super.addRow();

+    }

+

+    @Override

+    public EmptyTableRowData createRow() {

+      return new EmptyTableRowData();

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return EmptyTableRowData.class;

+    }

+

+    @Override

+    public EmptyTableRowData[] getRows() {

+      return (EmptyTableRowData[]) super.getRows();

+    }

+

+    @Override

+    public EmptyTableRowData rowAt(int idx) {

+      return (EmptyTableRowData) super.rowAt(idx);

+    }

+

+    public void setRows(EmptyTableRowData[] rows) {

+      super.setRows(rows);

+    }

+

+    public static class EmptyTableRowData extends AbstractTableRowData {

+      private static final long serialVersionUID = 1L;

+

+      public EmptyTableRowData() {

+      }

+    }

+  }

+

+  public static class NoTable extends AbstractTableFieldBeanData {

+    private static final long serialVersionUID = 1L;

+

+    public NoTable() {

+    }

+

+    @Override

+    public AbstractTableRowData createRow() {

+      return new AbstractTableRowData() {

+        private static final long serialVersionUID = 1L;

+      };

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return AbstractTableRowData.class;

+    }

+  }

+

+  public static class Table extends AbstractTableFieldBeanData {

+    private static final long serialVersionUID = 1L;

+

+    public Table() {

+    }

+

+    @Override

+    public TableRowData addRow() {

+      return (TableRowData) super.addRow();

+    }

+

+    @Override

+    public TableRowData addRow(int rowState) {

+      return (TableRowData) super.addRow(rowState);

+    }

+

+    @Override

+    public TableRowData createRow() {

+      return new TableRowData();

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return TableRowData.class;

+    }

+

+    @Override

+    public TableRowData[] getRows() {

+      return (TableRowData[]) super.getRows();

+    }

+

+    @Override

+    public TableRowData rowAt(int idx) {

+      return (TableRowData) super.rowAt(idx);

+    }

+

+    public void setRows(TableRowData[] rows) {

+      super.setRows(rows);

+    }

+

+    public static class TableRowData extends AbstractTableRowData {

+      private static final long serialVersionUID = 1L;

+

+      public TableRowData() {

+      }

+

+      private String m_first;

+      private String m_second;

+

+      public String getFirst() {

+        return m_first;

+      }

+

+      public void setFirst(String first) {

+        m_first = first;

+      }

+

+      public String getSecond() {

+        return m_second;

+      }

+

+      public void setSecond(String second) {

+        m_second = second;

+      }

+    }

+  }

+}

diff --git a/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldExFormData.java b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldExFormData.java
new file mode 100644
index 0000000..658d8cf
--- /dev/null
+++ b/org.eclipse.scout.sdk.test/resources/operation/formData/formdata.shared/src/formdata/shared/services/process/replace/TableFieldExFormData.java
@@ -0,0 +1,200 @@
+package formdata.shared.services.process.replace;

+

+import org.eclipse.scout.commons.annotations.Replace;

+import org.eclipse.scout.rt.shared.data.basic.table.AbstractTableRowData;

+

+public class TableFieldExFormData extends TableFieldBaseFormData {

+  private static final long serialVersionUID = 1L;

+

+  public TableFieldExFormData() {

+  }

+

+  public EmptyTableExtended getEmptyTableExtended() {

+    return getFieldByClass(EmptyTableExtended.class);

+  }

+

+  public NoTableExtended getNoTableExtended() {

+    return getFieldByClass(NoTableExtended.class);

+  }

+

+  public TableExtended getTableExtended() {

+    return getFieldByClass(TableExtended.class);

+  }

+

+  @Replace

+  public static class EmptyTableExtended extends TableFieldBaseFormData.EmptyTable {

+    private static final long serialVersionUID = 1L;

+

+    public EmptyTableExtended() {

+    }

+

+    @Override

+    public TableExRowData addRow() {

+      return (TableExRowData) super.addRow();

+    }

+

+    @Override

+    public TableExRowData addRow(int rowState) {

+      return (TableExRowData) super.addRow(rowState);

+    }

+

+    @Override

+    public TableExRowData createRow() {

+      return new TableExRowData();

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return TableExRowData.class;

+    }

+

+    @Override

+    public TableExRowData[] getRows() {

+      return (TableExRowData[]) super.getRows();

+    }

+

+    @Override

+    public TableExRowData rowAt(int idx) {

+      return (TableExRowData) super.rowAt(idx);

+    }

+

+    public void setRows(TableExRowData[] rows) {

+      super.setRows(rows);

+    }

+

+    public static class TableExRowData extends TableFieldBaseFormData.EmptyTable.EmptyTableRowData {

+      private static final long serialVersionUID = 1L;

+

+      public TableExRowData() {

+      }

+

+      private String m_single;

+

+      public void setSingle(String single) {

+        m_single = single;

+      }

+

+      public String getSingle() {

+        return m_single;

+      }

+    }

+  }

+

+  @Replace

+  public static class NoTableExtended extends TableFieldBaseFormData.NoTable {

+    private static final long serialVersionUID = 1L;

+

+    public NoTableExtended() {

+    }

+

+    @Override

+    public NoTableExtendedRowData addRow() {

+      return (NoTableExtendedRowData) super.addRow();

+    }

+

+    @Override

+    public NoTableExtendedRowData addRow(int rowState) {

+      return (NoTableExtendedRowData) super.addRow(rowState);

+    }

+

+    @Override

+    public NoTableExtendedRowData createRow() {

+      return new NoTableExtendedRowData();

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return NoTableExtendedRowData.class;

+    }

+

+    @Override

+    public NoTableExtendedRowData[] getRows() {

+      return (NoTableExtendedRowData[]) super.getRows();

+    }

+

+    @Override

+    public NoTableExtendedRowData rowAt(int idx) {

+      return (NoTableExtendedRowData) super.rowAt(idx);

+    }

+

+    public void setRows(NoTableExtendedRowData[] rows) {

+      super.setRows(rows);

+    }

+

+    public static class NoTableExtendedRowData extends AbstractTableRowData {

+      private static final long serialVersionUID = 1L;

+

+      public NoTableExtendedRowData() {

+      }

+

+      private String m_newValue;

+

+      public void setNew(String newValue) {

+        m_newValue = newValue;

+      }

+

+      public String getNew() {

+        return m_newValue;

+      }

+    }

+  }

+

+  @Replace

+  public static class TableExtended extends TableFieldBaseFormData.Table {

+    private static final long serialVersionUID = 1L;

+

+    public TableExtended() {

+    }

+

+    @Override

+    public TableExRowData addRow(int rowState) {

+      return (TableExRowData) super.addRow(rowState);

+    }

+

+    @Override

+    public TableExRowData addRow() {

+      return (TableExRowData) super.addRow();

+    }

+

+    @Override

+    public TableExRowData createRow() {

+      return new TableExRowData();

+    }

+

+    @Override

+    public Class<? extends AbstractTableRowData> getRowType() {

+      return TableExRowData.class;

+    }

+

+    @Override

+    public TableExRowData[] getRows() {

+      return (TableExRowData[]) super.getRows();

+    }

+

+    @Override

+    public TableExRowData rowAt(int idx) {

+      return (TableExRowData) super.rowAt(idx);

+    }

+

+    public void setRows(TableExRowData[] rows) {

+      super.setRows(rows);

+    }

+

+    public static class TableExRowData extends TableFieldBaseFormData.Table.TableRowData {

+      private static final long serialVersionUID = 1L;

+

+      public TableExRowData() {

+      }

+

+      private Boolean m_booleanValue;

+

+      public void setBoolean(Boolean booleanValue) {

+        m_booleanValue = booleanValue;

+      }

+

+      public Boolean getBoolean() {

+        return m_booleanValue;

+      }

+    }

+  }

+}

diff --git a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/RuntimeClasses.java b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/RuntimeClasses.java
index 54119c2..ac243e9 100644
--- a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/RuntimeClasses.java
+++ b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/RuntimeClasses.java
@@ -115,6 +115,8 @@
   public static final String AbstractTable = "org.eclipse.scout.rt.client.ui.basic.table.AbstractTable"; // NO_UCD

   public static final String AbstractTableField = "org.eclipse.scout.rt.client.ui.form.fields.tablefield.AbstractTableField"; // NO_UCD

   public static final String AbstractTableFieldData = "org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldData"; // NO_UCD

+  public static final String AbstractTableFieldBeanData = "org.eclipse.scout.rt.shared.data.form.fields.tablefield.AbstractTableFieldBeanData"; // NO_UCD

+  public static final String AbstractTableRowData = "org.eclipse.scout.rt.shared.data.basic.table.AbstractTableRowData"; // NO_UCD

   public static final String AbstractTimeField = "org.eclipse.scout.rt.client.ui.form.fields.timefield.AbstractTimeField"; // NO_UCD

   public static final String AbstractToolButton = "org.eclipse.scout.rt.client.ui.action.tool.AbstractToolButton"; // NO_UCD

   public static final String AbstractTree = "org.eclipse.scout.rt.client.ui.basic.tree.AbstractTree"; // NO_UCD

diff --git a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FieldSourceBuilder.java b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FieldSourceBuilder.java
new file mode 100644
index 0000000..f57ba2d
--- /dev/null
+++ b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FieldSourceBuilder.java
@@ -0,0 +1,87 @@
+/*******************************************************************************

+ * Copyright (c) 2010 BSI Business Systems Integration AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     BSI Business Systems Integration AG - initial API and implementation

+ ******************************************************************************/

+package org.eclipse.scout.sdk.operation.form.formdata;

+

+import org.eclipse.jdt.core.Flags;

+import org.eclipse.jdt.core.JavaModelException;

+import org.eclipse.scout.sdk.util.signature.IImportValidator;

+import org.eclipse.scout.sdk.util.signature.SignatureUtility;

+

+/**

+ * Source builder for java field declarations (without getter and setter methods). By default, a private non-static

+ * and non-final field is created.

+ * 

+ * @since 3.8.2

+ */

+public class FieldSourceBuilder implements ISourceBuilder {

+

+  private String m_elementName;

+  private String m_signature;

+  private int m_flags;

+

+  public FieldSourceBuilder() {

+    // defaults

+    m_flags = Flags.AccPrivate;

+  }

+

+  @Override

+  public String createSource(IImportValidator validator) throws JavaModelException {

+    StringBuilder builder = new StringBuilder();

+    if (Flags.isPublic(getFlags())) {

+      builder.append("public ");

+    }

+    if (Flags.isPrivate(getFlags())) {

+      builder.append("private ");

+    }

+    if (Flags.isProtected(getFlags())) {

+      builder.append("protected ");

+    }

+    if (Flags.isStatic(getFlags())) {

+      builder.append("static ");

+    }

+    if (Flags.isFinal(getFlags())) {

+      builder.append("final ");

+    }

+    builder.append(SignatureUtility.getTypeReference(getSignature(), validator) + " ");

+    builder.append(getElementName() + ";");

+    return builder.toString();

+  }

+

+  @Override

+  public int getType() {

+    return PROPERTY_SOURCE_BUILDER;

+  }

+

+  @Override

+  public String getElementName() {

+    return m_elementName;

+  }

+

+  public void setElementName(String elementName) {

+    m_elementName = elementName;

+  }

+

+  public String getSignature() {

+    return m_signature;

+  }

+

+  public void setSignature(String signature) {

+    m_signature = signature;

+  }

+

+  public int getFlags() {

+    return m_flags;

+  }

+

+  public void setFlags(int flags) {

+    m_flags = flags;

+  }

+}

diff --git a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FormDataUtility.java b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FormDataUtility.java
index 53168d2..4dd9d56 100644
--- a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FormDataUtility.java
+++ b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/FormDataUtility.java
@@ -114,6 +114,9 @@
       if (superTypeHierarchy != null && superTypeHierarchy.contains(TypeUtility.getType(RuntimeClasses.AbstractTableFieldData))) {

         builder = new TableFieldSourceBuilder(formField, hierarchy);

       }

+      else if (superTypeHierarchy != null && superTypeHierarchy.contains(TypeUtility.getType(RuntimeClasses.AbstractTableFieldBeanData))) {

+        builder = new TableFieldBeanSourceBuilder(formField, hierarchy);

+      }

       else {

         builder = new CompositePrimaryTypeSourceBuilder(formField, hierarchy);

       }

@@ -135,6 +138,9 @@
     if (superTypeHierarchy != null && superTypeHierarchy.contains(TypeUtility.getType(RuntimeClasses.AbstractTableFieldData))) {

       builder = new TableFieldSourceBuilder(formField, hierarchy);

     }

+    else if (superTypeHierarchy != null && superTypeHierarchy.contains(TypeUtility.getType(RuntimeClasses.AbstractTableFieldBeanData))) {

+      builder = new TableFieldBeanSourceBuilder(formField, hierarchy);

+    }

     else {

       builder = new SourceBuilderWithProperties(formField);

     }

diff --git a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/ISourceBuilder.java b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/ISourceBuilder.java
index d41fb1a..1d528a1 100644
--- a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/ISourceBuilder.java
+++ b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/ISourceBuilder.java
@@ -21,6 +21,7 @@
   public static final int METHOD_SOURCE_BUILDER = 2;

   public static final int ANNOTATION_SOURCE_BUILDER = 3;

   public static final int CONSTANT_INT_SOURCE_BUILDER = 3;

+  public static final int PROPERTY_SOURCE_BUILDER = 5;

 

   String getElementName();

 

diff --git a/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/TableFieldBeanSourceBuilder.java b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/TableFieldBeanSourceBuilder.java
new file mode 100644
index 0000000..9742782
--- /dev/null
+++ b/org.eclipse.scout.sdk/src/org/eclipse/scout/sdk/operation/form/formdata/TableFieldBeanSourceBuilder.java
@@ -0,0 +1,253 @@
+/*******************************************************************************

+ * Copyright (c) 2010 BSI Business Systems Integration AG.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     BSI Business Systems Integration AG - initial API and implementation

+ ******************************************************************************/

+package org.eclipse.scout.sdk.operation.form.formdata;

+

+import org.eclipse.jdt.core.Flags;

+import org.eclipse.jdt.core.IType;

+import org.eclipse.jdt.core.JavaModelException;

+import org.eclipse.jdt.core.Signature;

+import org.eclipse.scout.commons.CompositeObject;

+import org.eclipse.scout.sdk.RuntimeClasses;

+import org.eclipse.scout.sdk.internal.ScoutSdk;

+import org.eclipse.scout.sdk.util.signature.SignatureUtility;

+import org.eclipse.scout.sdk.util.type.TypeFilters;

+import org.eclipse.scout.sdk.util.type.TypeUtility;

+import org.eclipse.scout.sdk.util.typecache.ITypeHierarchy;

+import org.eclipse.scout.sdk.workspace.type.ScoutTypeComparators;

+import org.eclipse.scout.sdk.workspace.type.ScoutTypeUtility;

+

+/**

+ * Source builder that creates form data classes for an ITableField. The generated form data element stores the data in

+ * ordinary java beans (which are implementing {@link RuntimeClasses#AbstractTableRowData}.

+ * 

+ * @since 3.8.2

+ */

+public class TableFieldBeanSourceBuilder extends SourceBuilderWithProperties {

+  private static final String TABLE_ROW_BEAN_SUFFIX = "RowData";

+  private final IType iTable = TypeUtility.getType(RuntimeClasses.ITable);

+  private final IType iColumn = TypeUtility.getType(RuntimeClasses.IColumn);

+

+  public TableFieldBeanSourceBuilder(IType tableField, ITypeHierarchy hierarchy) {

+    super(tableField);

+    // find table

+    IType table = findTable(tableField, hierarchy);

+    if (TypeUtility.exists(table)) {

+      visitTable(table, hierarchy);

+    }

+    else {

+      visitTable(null, hierarchy);

+    }

+  }

+

+  private IType findTable(IType tableField, ITypeHierarchy hierarchy) {

+    if (TypeUtility.exists(tableField)) {

+      IType[] tables = TypeUtility.getInnerTypes(tableField, TypeFilters.getSubtypeFilter(iTable, hierarchy), null);

+      if (tables.length > 0) {

+        if (tables.length > 1) {

+          ScoutSdk.logWarning("table field '" + tableField.getFullyQualifiedName() + "' contatins more than one table! Taking first for formdata creation.");

+        }

+        return tables[0];

+      }

+      else {

+        return findTable(hierarchy.getSuperclass(tableField), hierarchy);

+      }

+    }

+    return null;

+  }

+

+  protected void visitTable(IType table, ITypeHierarchy hierarchy) {

+    if (table == null) {

+      // createRow

+      String simpleTableRowDataName = RuntimeClasses.AbstractTableRowData.substring(RuntimeClasses.AbstractTableRowData.lastIndexOf(".") + 1);

+      MethodSourceBuilder createRow = addMethodOverride("createRow");

+      createRow.setReturnSignature(Signature.createTypeSignature(RuntimeClasses.AbstractTableRowData, true));

+      createRow.setSimpleBody("return new " + simpleTableRowDataName + "() {private static final long serialVersionUID = 1L;};");

+

+      // getRowType

+      MethodSourceBuilder getRowType = addMethodOverride("getRowType");

+      getRowType.setReturnSignature(Signature.createTypeSignature(Class.class.getName() + "<? extends " + RuntimeClasses.AbstractTableRowData + ">", true));

+      getRowType.setSimpleBody("return " + simpleTableRowDataName + ".class;");

+

+      return;

+    }

+

+    final IType[] columns = TypeUtility.getInnerTypes(table, TypeFilters.getSubtypeFilter(iColumn, hierarchy), ScoutTypeComparators.getOrderAnnotationComparator());

+

+    // table bean

+    String tableRowBeanName = getTableRowBeanName(table);

+    String tableBeanSignature = Signature.createTypeSignature(tableRowBeanName, false);

+    String tableBeanArraySignature = Signature.createArraySignature(tableBeanSignature, 1);

+

+    TypeSourceBuilder tableBeanBuilder = new TypeSourceBuilder(NL);

+    tableBeanBuilder.setElementName(tableRowBeanName);

+    tableBeanBuilder.setSuperTypeSignature(getTableRowDataSuperClassSignature(table, hierarchy));

+    tableBeanBuilder.setFlags(Flags.AccPublic | Flags.AccStatic);

+    addBuilder(tableBeanBuilder, CATEGORY_TYPE_FIELD);

+

+    for (int i = 0; i < columns.length; i++) {

+      IType column = columns[i];

+      try {

+        if (ScoutTypeUtility.isReplaceAnnotationPresent(column)) {

+          // replaced columns already have a column data

+          continue;

+        }

+

+        String upperColName = FormDataUtility.getBeanName(FormDataUtility.getFieldNameWithoutSuffix(column.getElementName()), true);

+        String lowerColName = FormDataUtility.getBeanName(FormDataUtility.getFieldNameWithoutSuffix(column.getElementName()), false);

+        String methodParameterName = FormDataUtility.getValidMethodParameterName(lowerColName);

+        String propertyName = "m_" + methodParameterName;

+        String colSignature = getColumnSignature(column, hierarchy);

+

+        // property

+        FieldSourceBuilder prop = new FieldSourceBuilder();

+        prop.setElementName(propertyName);

+        prop.setSignature(colSignature);

+        tableBeanBuilder.addBuilder(prop, new CompositeObject(CATEGORY_TYPE_TABLE_COLUMN, 1, i, 0, prop));

+

+        // setter

+        MethodSourceBuilder propSetter = new MethodSourceBuilder(NL);

+        propSetter.setElementName("set" + upperColName);

+        propSetter.addParameter(new MethodParameter(colSignature, methodParameterName));

+        propSetter.setSimpleBody(propertyName + " = " + methodParameterName + ";");

+        tableBeanBuilder.addBuilder(propSetter, new CompositeObject(CATEGORY_TYPE_TABLE_COLUMN, 2, i, 2, propSetter));

+

+        // getter

+        MethodSourceBuilder propGetter = new MethodSourceBuilder(NL);

+        propGetter.setSimpleBody("return " + propertyName + ";");

+        propGetter.setElementName("get" + upperColName);

+        propGetter.setReturnSignature(colSignature);

+        tableBeanBuilder.addBuilder(propGetter, new CompositeObject(CATEGORY_TYPE_TABLE_COLUMN, 2, i, 2, propGetter));

+      }

+      catch (JavaModelException e) {

+        ScoutSdk.logWarning("could not add column '" + column.getFullyQualifiedName() + "' to form data.", e);

+      }

+    }

+

+    // getRows

+    MethodSourceBuilder getRows = addMethodOverride("getRows");

+    getRows.setReturnSignature(tableBeanArraySignature);

+    getRows.setSimpleBody("return (" + tableRowBeanName + "[]) super.getRows();");

+

+    // setRows

+    MethodSourceBuilder setRows = new MethodSourceBuilder(NL);

+    setRows.setElementName("setRows");

+    setRows.addParameter(new MethodParameter(tableBeanArraySignature, "rows"));

+    setRows.setSimpleBody("super.setRows(rows);");

+    addBuilder(setRows, CATEGORY_MEHTOD);

+

+    // rowAt

+    MethodSourceBuilder rowAt = addMethodOverride("rowAt");

+    rowAt.setReturnSignature(tableBeanSignature);

+    rowAt.addParameter(new MethodParameter(Signature.SIG_INT, "idx"));

+    rowAt.setSimpleBody("return (" + tableRowBeanName + ") super.rowAt(idx);");

+

+    // addRow

+    MethodSourceBuilder addRow = addMethodOverride("addRow");

+    addRow.setReturnSignature(tableBeanSignature);

+    addRow.setSimpleBody("return (" + tableRowBeanName + ") super.addRow();");

+

+    // addRowWithRowState

+    MethodSourceBuilder addRowWithRowState = addMethodOverride("addRow");

+    addRowWithRowState.setReturnSignature(tableBeanSignature);

+    addRowWithRowState.addParameter(new MethodParameter(Signature.SIG_INT, "rowState"));

+    addRowWithRowState.setSimpleBody("return (" + tableRowBeanName + ") super.addRow(rowState);");

+

+    // createRow

+    MethodSourceBuilder createRow = addMethodOverride("createRow");

+    createRow.setReturnSignature(tableBeanSignature);

+    createRow.setSimpleBody("return new " + tableRowBeanName + "();");

+

+    // getRowType

+    MethodSourceBuilder getRowType = addMethodOverride("getRowType");

+    getRowType.setReturnSignature(Signature.createTypeSignature(Class.class.getName() + "<? extends " + RuntimeClasses.AbstractTableRowData + ">", true));

+    getRowType.setSimpleBody("return " + tableRowBeanName + ".class;");

+  }

+

+  protected String getTableRowBeanName(IType table) {

+    String tableRowBeanName = table.getElementName();

+    if (iTable.equals(table) || "table".equalsIgnoreCase(tableRowBeanName)) {

+      // use table fields name

+      tableRowBeanName = FormDataUtility.getFieldNameWithoutSuffix(table.getDeclaringType().getElementName());

+    }

+    tableRowBeanName = tableRowBeanName + TABLE_ROW_BEAN_SUFFIX;

+    return tableRowBeanName;

+  }

+

+  /**

+   * Creates, adds and returns a {@link MethodSourceBuilder} with the given name. The {@link Override} annotation

+   * builder is already attached. Note: parametrs, return type and the method body must be set by the caller.

+   * 

+   * @param methodName

+   * @return

+   */

+  private MethodSourceBuilder addMethodOverride(String methodName) {

+    MethodSourceBuilder method = new MethodSourceBuilder(NL);

+    method.setElementName(methodName);

+    method.addAnnotation(new AnnotationSourceBuilder(Signature.createTypeSignature(Override.class.getName(), true)));

+    addBuilder(method, CATEGORY_MEHTOD);

+    return method;

+  }

+

+  /**

+   * Computes the given column's type signature that is also the type of the property generated in the table row data.

+   * 

+   * @param type

+   * @param columnHierarchy

+   * @return

+   * @throws JavaModelException

+   */

+  private String getColumnSignature(IType type, ITypeHierarchy columnHierarchy) throws JavaModelException {

+    if (type == null || Object.class.getName().equals(type.getFullyQualifiedName())) {

+      return null;

+    }

+    IType superType = columnHierarchy.getSuperclass(type);

+    if (TypeUtility.exists(superType)) {

+      if (TypeUtility.isGenericType(superType)) {

+        String superTypeSig = type.getSuperclassTypeSignature();

+        return SignatureUtility.getResolvedSignature(Signature.getTypeArguments(superTypeSig)[0], type);

+      }

+      else {

+        return getColumnSignature(superType, columnHierarchy);

+      }

+    }

+    else {

+      return null;

+    }

+  }

+

+  /**

+   * Computes the super class signature of the AbstractTableRowData bean created by this builder.

+   * 

+   * @param table

+   * @param hierarchy

+   * @return

+   */

+  private String getTableRowDataSuperClassSignature(IType table, ITypeHierarchy hierarchy) {

+    try {

+      IType parentTable = hierarchy.getSuperclass(table);

+      if (TypeUtility.exists(parentTable)) {

+        IType declaringType = parentTable.getDeclaringType();

+        if (TypeUtility.exists(declaringType)) {

+          IType formDataType = ScoutTypeUtility.getFormDataType(declaringType, hierarchy);

+          String parentTableRowBeanName = getTableRowBeanName(parentTable);

+          IType parentTableBeanData = formDataType.getType(parentTableRowBeanName);

+          if (TypeUtility.exists(parentTableBeanData)) {

+            return Signature.createTypeSignature(parentTableBeanData.getTypeQualifiedName(), false);

+          }

+        }

+      }

+    }

+    catch (JavaModelException e) {

+      ScoutSdk.logWarning("error while computing super class signature for [" + table + "]", e);

+    }

+    return Signature.createTypeSignature(RuntimeClasses.AbstractTableRowData, true);

+  }

+}