aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-08-22 20:14:30 +0300
committerLeif Åstrand <leif@vaadin.com>2012-08-22 20:14:30 +0300
commit38358ae25543433f8cc381101bc340adc7e5c67f (patch)
treee494d807e1031c04a3d07a0c56dd60be9ae6578a
parent02878bd07a38dc69fe415c7f60238817d2a7c434 (diff)
downloadvaadin-framework-38358ae25543433f8cc381101bc340adc7e5c67f.tar.gz
vaadin-framework-38358ae25543433f8cc381101bc340adc7e5c67f.zip
Support using public fields in state classes (#9324)
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java2
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java1
-rw-r--r--client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java77
-rw-r--r--client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java8
-rw-r--r--server/src/com/vaadin/terminal/gwt/server/JsonCodec.java170
-rw-r--r--server/src/com/vaadin/ui/Label.java10
-rw-r--r--shared/src/com/vaadin/shared/ui/label/LabelState.java21
-rw-r--r--shared/src/com/vaadin/shared/ui/orderedlayout/AbstractOrderedLayoutState.java2
-rw-r--r--tests/client-side/com/vaadin/terminal/gwt/server/JSONSerializerTest.java18
9 files changed, 218 insertions, 91 deletions
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
index 9a5b83f460..a2e61947e8 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/ConnectorBundleLoaderFactory.java
@@ -219,7 +219,7 @@ public class ConnectorBundleLoaderFactory extends Generator {
writeClassLiteral(w, property.getBeanType());
w.print(", \"");
w.print(escape(property.getName()));
- w.print("\", new Invoker() {");
+ w.println("\", new Invoker() {");
w.indent();
w.println("public Object invoke(Object bean, Object[] params) {");
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
index ad6b1eb102..7515124a5a 100644
--- a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/ConnectorBundle.java
@@ -372,6 +372,7 @@ public class ConnectorBundle {
HashSet<Property> properties = new HashSet<Property>();
properties.addAll(MethodProperty.findProperties(type));
+ properties.addAll(FieldProperty.findProperties(type));
return properties;
}
diff --git a/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java
new file mode 100644
index 0000000000..31555cc30b
--- /dev/null
+++ b/client-compiler/src/com/vaadin/terminal/gwt/widgetsetutils/metadata/FieldProperty.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2011 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.terminal.gwt.widgetsetutils.metadata;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.typeinfo.JClassType;
+import com.google.gwt.core.ext.typeinfo.JField;
+import com.google.gwt.user.rebind.SourceWriter;
+
+public class FieldProperty extends Property {
+
+ private FieldProperty(JClassType beanType, JField field) {
+ super(field.getName(), beanType, field.getType());
+ }
+
+ @Override
+ public void writeSetterBody(TreeLogger logger, SourceWriter w,
+ String beanVariable, String valueVariable) {
+ w.print("((%s) %s).%s = (%s)%s;", getBeanType()
+ .getQualifiedSourceName(), beanVariable, getName(),
+ getUnboxedPropertyTypeName(), valueVariable);
+ }
+
+ @Override
+ public void writeGetterBody(TreeLogger logger, SourceWriter w,
+ String beanVariable) {
+ w.print("return ((%s) %s).%s;", getBeanType().getQualifiedSourceName(),
+ beanVariable, getName());
+ }
+
+ public static Collection<FieldProperty> findProperties(JClassType type) {
+ Collection<FieldProperty> properties = new ArrayList<FieldProperty>();
+
+ List<JField> fields = getPublicFields(type);
+ for (JField field : fields) {
+ properties.add(new FieldProperty(type, field));
+ }
+
+ return properties;
+ }
+
+ private static List<JField> getPublicFields(JClassType type) {
+ Set<String> names = new HashSet<String>();
+ ArrayList<JField> fields = new ArrayList<JField>();
+ for (JClassType subType : type.getFlattenedSupertypeHierarchy()) {
+ JField[] subFields = subType.getFields();
+ for (JField field : subFields) {
+ if (field.isPublic() && !field.isStatic()
+ && names.add(field.getName())) {
+ fields.add(field);
+ }
+ }
+ }
+ return fields;
+ }
+
+}
diff --git a/client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java b/client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java
index 4280db8bc9..57f8c16952 100644
--- a/client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java
+++ b/client/src/com/vaadin/terminal/gwt/client/ui/label/LabelConnector.java
@@ -43,10 +43,10 @@ public class LabelConnector extends AbstractComponentConnector {
public void onStateChanged(StateChangeEvent stateChangeEvent) {
super.onStateChanged(stateChangeEvent);
boolean sinkOnloads = false;
- switch (getState().getContentMode()) {
+ switch (getState().contentMode) {
case PREFORMATTED:
PreElement preElement = Document.get().createPreElement();
- preElement.setInnerText(getState().getText());
+ preElement.setInnerText(getState().text);
// clear existing content
getWidget().setHTML("");
// add preformatted text to dom
@@ -54,14 +54,14 @@ public class LabelConnector extends AbstractComponentConnector {
break;
case TEXT:
- getWidget().setText(getState().getText());
+ getWidget().setText(getState().text);
break;
case XHTML:
case RAW:
sinkOnloads = true;
case XML:
- getWidget().setHTML(getState().getText());
+ getWidget().setHTML(getState().text);
break;
default:
getWidget().setText("");
diff --git a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
index 892f7ec526..1eee9c4f52 100644
--- a/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
+++ b/server/src/com/vaadin/terminal/gwt/server/JsonCodec.java
@@ -21,9 +21,10 @@ import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Array;
+import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
@@ -55,6 +56,107 @@ import com.vaadin.ui.ConnectorTracker;
*/
public class JsonCodec implements Serializable {
+ public static interface BeanProperty {
+ public Object getValue(Object bean) throws Exception;
+
+ public void setValue(Object bean, Object value) throws Exception;
+
+ public String getName();
+
+ public Type getType();
+ }
+
+ private static class FieldProperty implements BeanProperty {
+ private final Field field;
+
+ public FieldProperty(Field field) {
+ this.field = field;
+ }
+
+ @Override
+ public Object getValue(Object bean) throws Exception {
+ return field.get(bean);
+ }
+
+ @Override
+ public void setValue(Object bean, Object value) throws Exception {
+ field.set(bean, value);
+ }
+
+ @Override
+ public String getName() {
+ return field.getName();
+ }
+
+ @Override
+ public Type getType() {
+ return field.getGenericType();
+ }
+
+ public static Collection<FieldProperty> find(Class<?> type)
+ throws IntrospectionException {
+ Collection<FieldProperty> properties = new ArrayList<FieldProperty>();
+
+ Field[] fields = type.getFields();
+ for (Field field : fields) {
+ if (!Modifier.isStatic(field.getModifiers())) {
+ properties.add(new FieldProperty(field));
+ }
+ }
+
+ return properties;
+ }
+
+ }
+
+ private static class MethodProperty implements BeanProperty {
+ private final PropertyDescriptor pd;
+
+ public MethodProperty(PropertyDescriptor pd) {
+ this.pd = pd;
+ }
+
+ @Override
+ public Object getValue(Object bean) throws Exception {
+ Method readMethod = pd.getReadMethod();
+ return readMethod.invoke(bean);
+ }
+
+ @Override
+ public void setValue(Object bean, Object value) throws Exception {
+ pd.getWriteMethod().invoke(bean, value);
+ }
+
+ @Override
+ public String getName() {
+ String fieldName = pd.getWriteMethod().getName().substring(3);
+ fieldName = Character.toLowerCase(fieldName.charAt(0))
+ + fieldName.substring(1);
+ return fieldName;
+ }
+
+ public static Collection<MethodProperty> find(Class<?> type)
+ throws IntrospectionException {
+ Collection<MethodProperty> properties = new ArrayList<MethodProperty>();
+
+ for (PropertyDescriptor pd : Introspector.getBeanInfo(type)
+ .getPropertyDescriptors()) {
+ if (pd.getReadMethod() == null || pd.getWriteMethod() == null) {
+ continue;
+ }
+
+ properties.add(new MethodProperty(pd));
+ }
+ return properties;
+ }
+
+ @Override
+ public Type getType() {
+ return pd.getReadMethod().getGenericReturnType();
+ }
+
+ }
+
private static Map<Class<?>, String> typeToTransportType = new HashMap<Class<?>, String>();
/**
@@ -468,27 +570,6 @@ public class JsonCodec implements Serializable {
return set;
}
- /**
- * Returns the name that should be used as field name in the JSON. We strip
- * "set" from the setter, keeping the result - this is easy to do on both
- * server and client, avoiding some issues with cASE. E.g setZIndex()
- * becomes "zIndex". Also ensures that both getter and setter are present,
- * returning null otherwise.
- *
- * @param pd
- * @return the name to be used or null if both getter and setter are not
- * found.
- */
- static String getTransportFieldName(PropertyDescriptor pd) {
- if (pd.getReadMethod() == null || pd.getWriteMethod() == null) {
- return null;
- }
- String fieldName = pd.getWriteMethod().getName().substring(3);
- fieldName = Character.toLowerCase(fieldName.charAt(0))
- + fieldName.substring(1);
- return fieldName;
- }
-
private static Object decodeObject(Type targetType,
JSONObject serializedObject, ConnectorTracker connectorTracker)
throws JSONException {
@@ -497,31 +578,19 @@ public class JsonCodec implements Serializable {
try {
Object decodedObject = targetClass.newInstance();
- for (PropertyDescriptor pd : Introspector.getBeanInfo(targetClass)
- .getPropertyDescriptors()) {
+ for (BeanProperty property : getProperties(targetClass)) {
- String fieldName = getTransportFieldName(pd);
- if (fieldName == null) {
- continue;
- }
+ String fieldName = property.getName();
Object encodedFieldValue = serializedObject.get(fieldName);
- Type fieldType = pd.getReadMethod().getGenericReturnType();
+ Type fieldType = property.getType();
Object decodedFieldValue = decodeInternalOrCustomType(
fieldType, encodedFieldValue, connectorTracker);
- pd.getWriteMethod().invoke(decodedObject, decodedFieldValue);
+ property.setValue(decodedObject, decodedFieldValue);
}
return decodedObject;
- } catch (IllegalArgumentException e) {
- throw new JSONException(e);
- } catch (IllegalAccessException e) {
- throw new JSONException(e);
- } catch (InvocationTargetException e) {
- throw new JSONException(e);
- } catch (InstantiationException e) {
- throw new JSONException(e);
- } catch (IntrospectionException e) {
+ } catch (Exception e) {
throw new JSONException(e);
}
}
@@ -602,22 +671,27 @@ public class JsonCodec implements Serializable {
return JSONObject.NULL;
}
+ public static Collection<BeanProperty> getProperties(Class<?> type)
+ throws IntrospectionException {
+ Collection<BeanProperty> properties = new ArrayList<BeanProperty>();
+
+ properties.addAll(MethodProperty.find(type));
+ properties.addAll(FieldProperty.find(type));
+
+ return properties;
+ }
+
private static Object encodeObject(Object value, JSONObject diffState,
ConnectorTracker connectorTracker) throws JSONException {
JSONObject jsonMap = new JSONObject();
try {
- for (PropertyDescriptor pd : Introspector.getBeanInfo(
- value.getClass()).getPropertyDescriptors()) {
- String fieldName = getTransportFieldName(pd);
- if (fieldName == null) {
- continue;
- }
- Method getterMethod = pd.getReadMethod();
+ for (BeanProperty property : getProperties(value.getClass())) {
+ String fieldName = property.getName();
// We can't use PropertyDescriptor.getPropertyType() as it does
// not support generics
- Type fieldType = getterMethod.getGenericReturnType();
- Object fieldValue = getterMethod.invoke(value, (Object[]) null);
+ Type fieldType = property.getType();
+ Object fieldValue = property.getValue(value);
boolean equals = false;
Object diffStateValue = null;
if (diffState != null && diffState.has(fieldName)) {
diff --git a/server/src/com/vaadin/ui/Label.java b/server/src/com/vaadin/ui/Label.java
index 668b99a74c..10fa741058 100644
--- a/server/src/com/vaadin/ui/Label.java
+++ b/server/src/com/vaadin/ui/Label.java
@@ -168,7 +168,7 @@ public class Label extends AbstractComponent implements Property<String>,
public String getValue() {
if (getPropertyDataSource() == null) {
// Use internal value if we are running without a data source
- return getState().getText();
+ return getState().text;
}
return ConverterUtil.convertFromModel(getPropertyDataSource()
.getValue(), String.class, getConverter(), getLocale());
@@ -189,7 +189,7 @@ public class Label extends AbstractComponent implements Property<String>,
+ String.class.getName());
}
if (getPropertyDataSource() == null) {
- getState().setText((String) newStringValue);
+ getState().text = (String) newStringValue;
requestRepaint();
} else {
throw new IllegalStateException(
@@ -277,7 +277,7 @@ public class Label extends AbstractComponent implements Property<String>,
* @see ContentMode
*/
public ContentMode getContentMode() {
- return getState().getContentMode();
+ return getState().contentMode;
}
/**
@@ -293,7 +293,7 @@ public class Label extends AbstractComponent implements Property<String>,
throw new IllegalArgumentException("Content mode can not be null");
}
- getState().setContentMode(contentMode);
+ getState().contentMode = contentMode;
requestRepaint();
}
@@ -384,7 +384,7 @@ public class Label extends AbstractComponent implements Property<String>,
@Override
public void valueChange(Property.ValueChangeEvent event) {
// Update the internal value from the data source
- getState().setText(getValue());
+ getState().text = getValue();
requestRepaint();
fireValueChange();
diff --git a/shared/src/com/vaadin/shared/ui/label/LabelState.java b/shared/src/com/vaadin/shared/ui/label/LabelState.java
index 35e27bc63d..a91aeb0aa1 100644
--- a/shared/src/com/vaadin/shared/ui/label/LabelState.java
+++ b/shared/src/com/vaadin/shared/ui/label/LabelState.java
@@ -18,23 +18,6 @@ package com.vaadin.shared.ui.label;
import com.vaadin.shared.ComponentState;
public class LabelState extends ComponentState {
- private ContentMode contentMode = ContentMode.TEXT;
- private String text = "";
-
- public ContentMode getContentMode() {
- return contentMode;
- }
-
- public void setContentMode(ContentMode contentMode) {
- this.contentMode = contentMode;
- }
-
- public String getText() {
- return text;
- }
-
- public void setText(String text) {
- this.text = text;
- }
-
+ public ContentMode contentMode = ContentMode.TEXT;
+ public String text = "";
}
diff --git a/shared/src/com/vaadin/shared/ui/orderedlayout/AbstractOrderedLayoutState.java b/shared/src/com/vaadin/shared/ui/orderedlayout/AbstractOrderedLayoutState.java
index 3fa2ad771c..35456ab9ac 100644
--- a/shared/src/com/vaadin/shared/ui/orderedlayout/AbstractOrderedLayoutState.java
+++ b/shared/src/com/vaadin/shared/ui/orderedlayout/AbstractOrderedLayoutState.java
@@ -25,7 +25,7 @@ import com.vaadin.shared.ui.AlignmentInfo;
public class AbstractOrderedLayoutState extends AbstractLayoutState {
private boolean spacing = false;
- public HashMap<Connector, ChildComponentData> childData = new HashMap<Connector, ChildComponentData>();
+ private HashMap<Connector, ChildComponentData> childData = new HashMap<Connector, ChildComponentData>();
private int marginsBitmask = 0;
diff --git a/tests/client-side/com/vaadin/terminal/gwt/server/JSONSerializerTest.java b/tests/client-side/com/vaadin/terminal/gwt/server/JSONSerializerTest.java
index 16cc0ede98..7775b667a1 100644
--- a/tests/client-side/com/vaadin/terminal/gwt/server/JSONSerializerTest.java
+++ b/tests/client-side/com/vaadin/terminal/gwt/server/JSONSerializerTest.java
@@ -1,7 +1,7 @@
package com.vaadin.terminal.gwt.server;
/*
- * Copyright 2011 Vaadin Ltd.
+ * Copyright 2011 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -15,9 +15,6 @@ package com.vaadin.terminal.gwt.server;
* License for the specific language governing permissions and limitations under
* the License.
*/
-import java.beans.BeanInfo;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.HashMap;
@@ -28,6 +25,7 @@ import junit.framework.TestCase;
import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState;
import com.vaadin.terminal.gwt.client.communication.JsonDecoder;
import com.vaadin.terminal.gwt.client.communication.JsonEncoder;
+import com.vaadin.terminal.gwt.server.JsonCodec.BeanProperty;
/**
* Tests for {@link JsonCodec}, {@link JsonEncoder}, {@link JsonDecoder}
@@ -118,15 +116,9 @@ public class JSONSerializerTest extends TestCase {
}
private boolean equalsBean(Object o1, Object o2) throws Exception {
- BeanInfo beanInfo = Introspector.getBeanInfo(o1.getClass());
- for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) {
- String fieldName = JsonCodec.getTransportFieldName(pd);
- if (fieldName == null) {
- continue;
- }
-
- Object c1 = pd.getReadMethod().invoke(o1);
- Object c2 = pd.getReadMethod().invoke(o2);
+ for (BeanProperty property : JsonCodec.getProperties(o1.getClass())) {
+ Object c1 = property.getValue(o1);
+ Object c2 = property.getValue(o2);
if (!equals(c1, c2)) {
return false;
}