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.tags/7.0.0.alpha3
@@ -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; | |||
} | |||
} |
@@ -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); | |||
/** |
@@ -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; | |||
} |
@@ -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 |
@@ -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; | |||
} | |||
@@ -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); |
@@ -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(); | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} |
@@ -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(); | |||
@@ -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; | |||
@@ -820,20 +819,28 @@ public abstract class AbstractComponent implements Component, MethodEventSource | |||
* @return new shared state object | |||
*/ | |||
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 */ |
@@ -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; | |||
} | |||
/** |