diff options
author | Artur Signell <artur@vaadin.com> | 2012-04-23 21:48:02 +0300 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2012-05-11 22:18:19 +0300 |
commit | badc5c3ee400b1225145de6532004b36d4ad14b9 (patch) | |
tree | d74f10eea1b05835fd8532eebf54bacfa55d0309 /src/com/vaadin | |
parent | bb5fca1bcaaa114175c45bf0e4d78a53ccee6c8a (diff) | |
download | vaadin-framework-badc5c3ee400b1225145de6532004b36d4ad14b9.tar.gz vaadin-framework-badc5c3ee400b1225145de6532004b36d4ad14b9.zip |
Initial support for sending difference in state (#8419)
Forces the shared state to be the type declared by getStateType (#8677)
Creates an empty object for reference when doing a full repaint, causing
only the differences between a freshly created object and the current
state to be sent.
Diffstat (limited to 'src/com/vaadin')
12 files changed, 225 insertions, 71 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java index 739c232a72..18b1afd813 100644 --- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java +++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java @@ -43,6 +43,7 @@ import com.vaadin.terminal.gwt.client.communication.JsonDecoder; import com.vaadin.terminal.gwt.client.communication.JsonEncoder; import com.vaadin.terminal.gwt.client.communication.MethodInvocation; import com.vaadin.terminal.gwt.client.communication.RpcManager; +import com.vaadin.terminal.gwt.client.communication.SerializerMap; import com.vaadin.terminal.gwt.client.communication.SharedState; import com.vaadin.terminal.gwt.client.communication.StateChangeEvent; import com.vaadin.terminal.gwt.client.ui.AbstractComponentConnector; @@ -102,6 +103,9 @@ public class ApplicationConnection { public static final String PARAM_UNLOADBURST = "onunloadburst"; + private static SerializerMap serializerMap = GWT + .create(SerializerMap.class); + /** * A string that, if found in a non-JSON response to a UIDL request, will * cause the browser to refresh the page. If followed by a colon, optional @@ -1414,8 +1418,8 @@ public class ApplicationConnection { states.getJavaScriptObject(connectorId)); Object state = JsonDecoder.decodeValue( - stateDataAndType, connectorMap, - ApplicationConnection.this); + stateDataAndType, connector.getState(), + connectorMap, ApplicationConnection.this); connector.setState((SharedState) state); StateChangeEvent event = GWT @@ -1569,7 +1573,8 @@ public class ApplicationConnection { Object[] parameters = new Object[parametersJson.size()]; for (int j = 0; j < parametersJson.size(); ++j) { parameters[j] = JsonDecoder.decodeValue( - (JSONArray) parametersJson.get(j), getConnectorMap(), this); + (JSONArray) parametersJson.get(j), null, getConnectorMap(), + this); } return new MethodInvocation(connectorId, interfaceName, methodName, parameters); @@ -2439,4 +2444,8 @@ public class ApplicationConnection { LayoutManager getLayoutManager() { return layoutManager; } + + public SerializerMap getSerializerMap() { + return serializerMap; + } } diff --git a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java index c626d31d0a..5f82e339f4 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JSONSerializer.java @@ -33,12 +33,14 @@ public interface JSONSerializer<T> { * * @param jsonValue * JSON map from property name to property value + * @param target + * The object to write the deserialized values to * @param idMapper * mapper from paintable id to paintable, used to decode * references to paintables * @return A deserialized object */ - T deserialize(JSONObject jsonValue, ConnectorMap idMapper, + T deserialize(JSONObject jsonValue, T target, ConnectorMap idMapper, ApplicationConnection connection); /** diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java index 2b58c13f3e..790b5cb305 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonDecoder.java @@ -12,7 +12,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import com.google.gwt.core.client.GWT; import com.google.gwt.json.client.JSONArray; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONString; @@ -33,7 +32,6 @@ import com.vaadin.terminal.gwt.client.ServerConnector; * @since 7.0 */ public class JsonDecoder { - static SerializerMap serializerMap = GWT.create(SerializerMap.class); /** * Decode a JSON array with two elements (type and value) into a client-side @@ -48,14 +46,15 @@ public class JsonDecoder { * reference to the current ApplicationConnection * @return decoded value (does not contain JSON types) */ - public static Object decodeValue(JSONArray jsonArray, + public static Object decodeValue(JSONArray jsonArray, Object target, ConnectorMap idMapper, ApplicationConnection connection) { String type = ((JSONString) jsonArray.get(0)).stringValue(); - return decodeValue(type, jsonArray.get(1), idMapper, connection); + return decodeValue(type, jsonArray.get(1), target, idMapper, connection); } private static Object decodeValue(String variableType, Object value, - ConnectorMap idMapper, ApplicationConnection connection) { + Object target, ConnectorMap idMapper, + ApplicationConnection connection) { Object val = null; // TODO type checks etc. if (JsonEncoder.VTYPE_NULL.equals(variableType)) { @@ -92,18 +91,25 @@ public class JsonDecoder { } else if (JsonEncoder.VTYPE_CONNECTOR.equals(variableType)) { val = idMapper.getConnector(((JSONString) value).stringValue()); } else { - // object, class name as type - JSONSerializer serializer = serializerMap - .getSerializer(variableType); - // TODO handle case with no serializer found - Object object = serializer.deserialize((JSONObject) value, + return decodeObject(variableType, (JSONObject) value, target, idMapper, connection); - return object; } return val; } + private static Object decodeObject(String variableType, + JSONObject encodedValue, Object target, ConnectorMap idMapper, + ApplicationConnection connection) { + // object, class name as type + JSONSerializer<Object> serializer = connection.getSerializerMap() + .getSerializer(variableType); + // TODO handle case with no serializer found + Object object = serializer.deserialize(encodedValue, target, idMapper, + connection); + return object; + } + private static Map<String, Object> decodeMap(JSONObject jsonMap, ConnectorMap idMapper, ApplicationConnection connection) { HashMap<String, Object> map = new HashMap<String, Object>(); @@ -111,7 +117,7 @@ public class JsonDecoder { while (it.hasNext()) { String key = it.next(); map.put(key, - decodeValue((JSONArray) jsonMap.get(key), idMapper, + decodeValue((JSONArray) jsonMap.get(key), null, idMapper, connection)); } return map; @@ -126,8 +132,8 @@ public class JsonDecoder { String connectorId = it.next(); Connector connector = idMapper.getConnector(connectorId); map.put(connector, - decodeValue((JSONArray) jsonMap.get(connectorId), idMapper, - connection)); + decodeValue((JSONArray) jsonMap.get(connectorId), null, + idMapper, connection)); } return map; } @@ -153,7 +159,7 @@ public class JsonDecoder { for (int i = 0; i < jsonArray.size(); ++i) { // each entry always has two elements: type and value JSONArray entryArray = (JSONArray) jsonArray.get(i); - tokens.add(decodeValue(entryArray, idMapper, connection)); + tokens.add(decodeValue(entryArray, null, idMapper, connection)); } return tokens; } @@ -164,7 +170,7 @@ public class JsonDecoder { for (int i = 0; i < jsonArray.size(); ++i) { // each entry always has two elements: type and value JSONArray entryArray = (JSONArray) jsonArray.get(i); - tokens.add(decodeValue(entryArray, idMapper, connection)); + tokens.add(decodeValue(entryArray, null, idMapper, connection)); } return tokens; } diff --git a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java index fdc06b0e21..4a3515ff13 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java +++ b/src/com/vaadin/terminal/gwt/client/communication/JsonEncoder.java @@ -117,7 +117,7 @@ public class JsonEncoder { // Try to find a generated serializer object, class name is the // type transportType = value.getClass().getName(); - JSONSerializer serializer = JsonDecoder.serializerMap + JSONSerializer serializer = connection.getSerializerMap() .getSerializer(transportType); // TODO handle case with no serializer found diff --git a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java index 4fefc7f845..27a0d0118e 100644 --- a/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java +++ b/src/com/vaadin/terminal/gwt/client/communication/URLReference_Serializer.java @@ -11,13 +11,15 @@ import com.vaadin.terminal.gwt.client.ConnectorMap; public class URLReference_Serializer implements JSONSerializer<URLReference> { - public URLReference deserialize(JSONObject jsonValue, + public URLReference deserialize(JSONObject jsonValue, URLReference target, ConnectorMap idMapper, ApplicationConnection connection) { URLReference reference = GWT.create(URLReference.class); - JSONArray jsonURL = (JSONArray) jsonValue.get("URL"); - String URL = (String) JsonDecoder.decodeValue(jsonURL, idMapper, - connection); - reference.setURL(connection.translateVaadinUri(URL)); + if (jsonValue.containsKey("URL")) { + JSONArray jsonURL = (JSONArray) jsonValue.get("URL"); + String URL = (String) JsonDecoder.decodeValue(jsonURL, null, + idMapper, connection); + reference.setURL(connection.translateVaadinUri(URL)); + } return reference; } diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java index c57e7d8bc1..97cb3114b9 100644 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java @@ -803,14 +803,28 @@ public abstract class AbstractCommunicationManager implements Serializable { // client after component creation but before legacy UIDL // processing. JSONObject sharedStates = new JSONObject(); - for (Connector connector : dirtyVisibleConnectors) { + for (ClientConnector connector : dirtyVisibleConnectors) { SharedState state = connector.getState(); if (null != state) { // encode and send shared state try { - // FIXME Use declared type + Class<? extends SharedState> stateType = connector + .getStateType(); + SharedState referenceState = null; + if (repaintAll) { + // Use an empty state object as reference for full + // repaints + try { + referenceState = stateType.newInstance(); + } catch (Exception e) { + logger.log(Level.WARNING, + "Error creating reference object for state of type " + + stateType.getName()); + } + } JSONArray stateJsonArray = JsonCodec.encode(state, - state.getClass(), application); + referenceState, stateType, application); + sharedStates .put(connector.getConnectorId(), stateJsonArray); } catch (JSONException e) { @@ -900,9 +914,21 @@ public abstract class AbstractCommunicationManager implements Serializable { invocationJson.put(invocation.getMethodName()); JSONArray paramJson = new JSONArray(); for (int i = 0; i < invocation.getParameterTypes().length; ++i) { + Class<?> parameterType = invocation.getParameterTypes()[i]; + Object referenceParameter = null; + // TODO Use default values for RPC parameter types + // if (!JsonCodec.isInternalType(parameterType)) { + // try { + // referenceParameter = parameterType.newInstance(); + // } catch (Exception e) { + // logger.log(Level.WARNING, + // "Error creating reference object for parameter of type " + // + parameterType.getName()); + // } + // } paramJson.put(JsonCodec.encode( - invocation.getParameters()[i], - invocation.getParameterTypes()[i], application)); + invocation.getParameters()[i], referenceParameter, + parameterType, application)); } invocationJson.put(paramJson); rpcCalls.put(invocationJson); diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java index 7a1f0fad68..7e74c26fb1 100644 --- a/src/com/vaadin/terminal/gwt/server/ClientConnector.java +++ b/src/com/vaadin/terminal/gwt/server/ClientConnector.java @@ -6,6 +6,7 @@ package com.vaadin.terminal.gwt.server; import java.util.List; import com.vaadin.terminal.gwt.client.Connector; +import com.vaadin.terminal.gwt.client.communication.SharedState; /** * Interface implemented by all connectors that are capable of communicating @@ -35,4 +36,12 @@ public interface ClientConnector extends Connector, RpcTarget { * @return true if the connector can receive messages, false otherwise */ public boolean isConnectorEnabled(); + + /** + * Returns the type of the shared state for this connector + * + * @return The type of the state. Must never return null. + */ + public Class<? extends SharedState> getStateType(); + } diff --git a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java index d3fe5a890b..f6c96557ea 100644 --- a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java +++ b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java @@ -238,4 +238,8 @@ public class DragAndDropService implements VariableOwner, ClientConnector { // TODO Use rpc for drag'n'drop return null; } + + public Class<? extends SharedState> getStateType() { + return SharedState.class; + } } diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java index 375cce4161..c88a1c828c 100644 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ b/src/com/vaadin/terminal/gwt/server/JsonCodec.java @@ -419,11 +419,11 @@ public class JsonCodec implements Serializable { @Deprecated private static JSONArray encode(Object value, Application application) throws JSONException { - return encode(value, null, application); + return encode(value, null, null, application); } - public static JSONArray encode(Object value, Class<?> valueType, - Application application) throws JSONException { + public static JSONArray encode(Object value, Object referenceValue, + Type valueType, Application application) throws JSONException { if (null == value) { return encodeNull(); @@ -453,7 +453,8 @@ public class JsonCodec implements Serializable { "Unable to serialize unsupported type: " + valueType); } Collection<?> collection = (Collection<?>) value; - JSONArray jsonArray = encodeCollection(collection, application); + JSONArray jsonArray = encodeCollection(valueType, collection, + application); return combineTypeAndValue(internalTransportType, jsonArray); } else if (value instanceof Object[]) { @@ -486,8 +487,9 @@ public class JsonCodec implements Serializable { } else { // Any object that we do not know how to encode we encode by looping // through fields - return combineTypeAndValue(getCustomTransportType(valueType), - encodeObject(value, application)); + return combineTypeAndValue( + getCustomTransportType((Class<?>) valueType), + encodeObject(value, referenceValue, application)); } } @@ -495,22 +497,40 @@ public class JsonCodec implements Serializable { return combineTypeAndValue(JsonEncoder.VTYPE_NULL, JSONObject.NULL); } - private static Object encodeObject(Object value, Application application) - throws JSONException { + private static Object encodeObject(Object value, Object referenceValue, + Application application) throws JSONException { JSONObject jsonMap = new JSONObject(); try { for (PropertyDescriptor pd : Introspector.getBeanInfo( value.getClass()).getPropertyDescriptors()) { - Class<?> fieldType = pd.getPropertyType(); String fieldName = getTransportFieldName(pd); if (fieldName == null) { continue; } Method getterMethod = pd.getReadMethod(); + // We can't use PropertyDescriptor.getPropertyType() as it does + // not support generics + Type fieldType = getterMethod.getGenericReturnType(); Object fieldValue = getterMethod.invoke(value, (Object[]) null); - jsonMap.put(fieldName, - encode(fieldValue, fieldType, application)); + boolean equals = false; + Object referenceFieldValue = null; + if (referenceValue != null) { + referenceFieldValue = getterMethod.invoke(referenceValue, + (Object[]) null); + equals = equals(fieldValue, referenceFieldValue); + } + if (!equals) { + jsonMap.put( + fieldName, + encode(fieldValue, referenceFieldValue, fieldType, + application)); + // } else { + // System.out.println("Skipping field " + fieldName + // + " of type " + fieldType.getName() + // + " for object " + value.getClass().getName() + // + " as " + fieldValue + "==" + referenceFieldValue); + } } } catch (Exception e) { // TODO: Should exceptions be handled in a different way? @@ -519,24 +539,56 @@ public class JsonCodec implements Serializable { return jsonMap; } + /** + * Compares the value with the reference. If they match, returns true. + * + * @param fieldValue + * @param referenceValue + * @return + */ + private static boolean equals(Object fieldValue, Object referenceValue) { + if (fieldValue == null) { + return referenceValue == null; + } + + if (fieldValue.equals(referenceValue)) { + return true; + } + + return false; + } + private static JSONArray encodeArrayContents(Object[] array, Application application) throws JSONException { JSONArray jsonArray = new JSONArray(); for (Object o : array) { - jsonArray.put(encode(o, null, application)); + jsonArray.put(encode(o, null, null, application)); } return jsonArray; } - private static JSONArray encodeCollection(Collection collection, - Application application) throws JSONException { + private static JSONArray encodeCollection(Type targetType, + Collection collection, Application application) + throws JSONException { JSONArray jsonArray = new JSONArray(); for (Object o : collection) { - jsonArray.put(encode(o, application)); + jsonArray.put(encodeChild(targetType, 0, o, application)); } return jsonArray; } + private static JSONArray encodeChild(Type targetType, int typeIndex, + Object o, Application application) throws JSONException { + if (targetType instanceof ParameterizedType) { + Type childType = ((ParameterizedType) targetType) + .getActualTypeArguments()[typeIndex]; + // Encode using the given type + return encode(o, null, childType, application); + } else { + return encode(o, application); + } + } + private static JSONObject encodeMapContents(Map<Object, Object> map, Application application) throws JSONException { JSONObject jsonMap = new JSONObject(); @@ -551,7 +603,8 @@ public class JsonCodec implements Serializable { "Only maps with String/Connector keys are currently supported (#8602)"); } - jsonMap.put((String) mapKey, encode(mapValue, null, application)); + jsonMap.put((String) mapKey, + encode(mapValue, null, null, application)); } return jsonMap; } diff --git a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java index d3ed9fe484..3b6ab8cdba 100644 --- a/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java +++ b/src/com/vaadin/terminal/gwt/widgetsetutils/SerializerGenerator.java @@ -106,7 +106,8 @@ public class SerializerGenerator extends Generator { composer.addImport(JsonDecoder.class.getName()); // composer.addImport(VaadinSerializer.class.getName()); - composer.addImplementedInterface(JSONSerializer.class.getName()); + composer.addImplementedInterface(JSONSerializer.class.getName() + "<" + + beanQualifiedSourceName + ">"); SourceWriter sourceWriter = composer.createSourceWriter(context, printWriter); @@ -117,7 +118,7 @@ public class SerializerGenerator extends Generator { // public JSONValue serialize(Object value, ConnectorMap idMapper, // ApplicationConnection connection) { sourceWriter.println("public " + JSONObject.class.getName() - + " serialize(" + Object.class.getName() + " value, " + + " serialize(" + beanQualifiedSourceName + " value, " + ConnectorMap.class.getName() + " idMapper, " + ApplicationConnection.class.getName() + " connection) {"); sourceWriter.indent(); @@ -152,13 +153,20 @@ public class SerializerGenerator extends Generator { // Deserializer sourceWriter.println("public " + beanQualifiedSourceName + " deserialize(" + JSONObject.class.getName() + " jsonValue, " + + beanQualifiedSourceName + " target, " + ConnectorMap.class.getName() + " idMapper, " + ApplicationConnection.class.getName() + " connection) {"); sourceWriter.indent(); - // VButtonState state = GWT.create(VButtonState.class); - sourceWriter.println(beanQualifiedSourceName + " state = GWT.create(" - + beanQualifiedSourceName + ".class);"); + // if (target == null) { + sourceWriter.println("if (target == null) {"); + sourceWriter.indent(); + // target = GWT.create(VButtonState.class); + sourceWriter.println("target = GWT.create(" + beanQualifiedSourceName + + ".class);"); + sourceWriter.outdent(); + sourceWriter.println("}"); + for (JMethod method : getSetters(beanType)) { String setterName = method.getName(); String fieldName = setterName.substring(3); // setZIndex() -> ZIndex @@ -167,30 +175,59 @@ public class SerializerGenerator extends Generator { logger.log(Type.DEBUG, "* Processing field " + fieldName + " in " + beanQualifiedSourceName + " (" + beanType.getName() + ")"); + // if (jsonValue.containsKey("height")) { + sourceWriter.println("if (jsonValue.containsKey(\"" + fieldName + + "\")) {"); + sourceWriter.indent(); String jsonFieldName = "json_" + fieldName; // JSONArray json_Height = (JSONArray) jsonValue.get("height"); sourceWriter.println("JSONArray " + jsonFieldName + " = (JSONArray) jsonValue.get(\"" + fieldName + "\");"); - // state.setHeight((String) - // JsonDecoder.decodeValue(jsonFieldValue,idMapper, connection)); - String fieldType; + String getterName = "get" + fieldName; JPrimitiveType primitiveType = setterParameterType.isPrimitive(); if (primitiveType != null) { // This is a primitive type -> must used the boxed type fieldType = primitiveType.getQualifiedBoxedSourceName(); + if (primitiveType == JPrimitiveType.BOOLEAN) { + getterName = "is" + fieldName; + } } else { fieldType = setterParameterType.getQualifiedSourceName(); } - sourceWriter.println("state." + setterName + "((" + fieldType + // String referenceValue; + sourceWriter.println(fieldType + " referenceValue;"); + // if (target == null) { + sourceWriter.println("if (target == null) {"); + sourceWriter.indent(); + // referenceValue = null; + sourceWriter.println("referenceValue = null;"); + // } else { + sourceWriter.println("} else {"); + // referenceValue = target.getHeight(); + sourceWriter.println("referenceValue = target." + getterName + + "();"); + // } + sourceWriter.outdent(); + sourceWriter.println("}"); + + // target.setHeight((String) + // JsonDecoder.decodeValue(jsonFieldValue,referenceValue, idMapper, + // connection)); + sourceWriter.println("target." + setterName + "((" + fieldType + ") " + JsonDecoder.class.getName() + ".decodeValue(" - + jsonFieldName + ", idMapper, connection));"); + + jsonFieldName + + ", referenceValue, idMapper, connection));"); + + // } ... end of if contains + sourceWriter.println("}"); + sourceWriter.outdent(); } - // return state; - sourceWriter.println("return state;"); + // return target; + sourceWriter.println("return target;"); sourceWriter.println("}"); sourceWriter.outdent(); diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java index 79a07ae00e..554d7806f9 100644 --- a/src/com/vaadin/ui/AbstractComponent.java +++ b/src/com/vaadin/ui/AbstractComponent.java @@ -18,7 +18,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -821,19 +820,27 @@ public abstract class AbstractComponent implements Component, MethodEventSource */ protected ComponentState createState() { try { + return getStateType().newInstance(); + } catch (Exception e) { + throw new RuntimeException( + "Error creating state of type " + getStateType().getName() + + " for " + getClass().getName(), e); + } + } + + /* (non-Javadoc) + * @see com.vaadin.terminal.gwt.server.ClientConnector#getStateType() + */ + public Class<? extends ComponentState> getStateType() { + try { Method m = getClass().getMethod("getState", (Class[]) null); Class<? extends ComponentState> type = (Class<? extends ComponentState>) m .getReturnType(); - return type.newInstance(); + return type; } catch (Exception e) { - getLogger().log( - Level.INFO, - "Error determining state object class for " - + getClass().getName()); + throw new RuntimeException("Error finding state type for " + + getClass().getName(), e); } - - // Fall back to ComponentState if detection fails for some reason. - return new ComponentState(); } /* Documentation copied from interface */ diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java index 405ae8da93..07dd5a0f69 100644 --- a/src/com/vaadin/ui/Root.java +++ b/src/com/vaadin/ui/Root.java @@ -30,7 +30,6 @@ import com.vaadin.terminal.Resource; import com.vaadin.terminal.Vaadin6Component; import com.vaadin.terminal.WrappedRequest; import com.vaadin.terminal.WrappedRequest.BrowserDetails; -import com.vaadin.terminal.gwt.client.ComponentState; import com.vaadin.terminal.gwt.client.MouseEventDetails; import com.vaadin.terminal.gwt.client.ui.notification.VNotification; import com.vaadin.terminal.gwt.client.ui.root.RootServerRpc; @@ -475,10 +474,10 @@ public abstract class Root extends AbstractComponentContainer implements } @Override - protected ComponentState createState() { + public Class<? extends RootState> getStateType() { // This is a workaround for a problem with creating the correct state // object during build - return new RootState(); + return RootState.class; } /** |