Browse Source

Optimizes memory and CPU usage in JSONCodec (#13545)

The null element and the empty JSONArray are frequently created and used
as temporary objects to be encoded by the json encoder. Because they are
never manipulated it is possible to reuse the same empty element again
and save a significant amount of temp objects.
This also helps jsonEquals, which then can return faster due to:
if (fieldValue == referenceValue) return true

jsonEquals does not need to check the referenceValue for JSONobject.NULL.
The invoking code makes sure this never happens.
Boolean and Integer values are very often and much more efficiently
compared directly instead of using toString.

Change-Id: I5fd736427019406469357cda1115d2683b7a5e2b
tags/7.2.0.beta1
Fabian Lange 10 years ago
parent
commit
52db8e5457

+ 28
- 10
server/src/com/vaadin/server/JsonCodec.java View File

@@ -62,6 +62,25 @@ import com.vaadin.ui.ConnectorTracker;
*/
public class JsonCodec implements Serializable {

/* Immutable Encode Result representing null */
private static final EncodeResult ENCODE_RESULT_NULL = new EncodeResult(
JSONObject.NULL);

/* Immutable empty JSONArray */
private static final JSONArray EMPTY_JSON_ARRAY = new JSONArray() {
@Override
public JSONArray put(Object value) {
throw new UnsupportedOperationException(
"Immutable empty JSONArray.");
};

@Override
public JSONArray put(int index, Object value) {
throw new UnsupportedOperationException(
"Immutable empty JSONArray.");
};
};

public static interface BeanProperty extends Serializable {
public Object getValue(Object bean) throws Exception;

@@ -635,7 +654,7 @@ public class JsonCodec implements Serializable {
}

if (null == value) {
return encodeNull();
return ENCODE_RESULT_NULL;
}

if (value instanceof String[]) {
@@ -680,7 +699,7 @@ public class JsonCodec implements Serializable {
if (value instanceof Component
&& !(LegacyCommunicationManager
.isComponentVisibleToClient((Component) value))) {
return encodeNull();
return ENCODE_RESULT_NULL;
}
return new EncodeResult(connector.getConnectorId());
} else if (value instanceof Enum) {
@@ -701,10 +720,6 @@ public class JsonCodec implements Serializable {
}
}

private static EncodeResult encodeNull() {
return new EncodeResult(JSONObject.NULL);
}

public static Collection<BeanProperty> getProperties(Class<?> type)
throws IntrospectionException {
Collection<BeanProperty> cachedProperties = typePropertyCache.get(type);
@@ -781,14 +796,17 @@ public class JsonCodec implements Serializable {
if (fieldValue == JSONObject.NULL) {
fieldValue = null;
}
if (referenceValue == JSONObject.NULL) {
referenceValue = null;
}

if (fieldValue == referenceValue) {
return true;
} else if (fieldValue == null || referenceValue == null) {
return false;
} else if (fieldValue instanceof Integer
&& referenceValue instanceof Integer) {
return ((Integer) fieldValue).equals(referenceValue);
} else if (fieldValue instanceof Boolean
&& referenceValue instanceof Boolean) {
return ((Boolean) fieldValue).equals(referenceValue);
} else {
return fieldValue.toString().equals(referenceValue.toString());
}
@@ -849,7 +867,7 @@ public class JsonCodec implements Serializable {
if (map.isEmpty()) {
// Client -> server encodes empty map as an empty array because of
// #8906. Do the same for server -> client to maintain symmetry.
return new JSONArray();
return EMPTY_JSON_ARRAY;
}

if (keyType == String.class) {

+ 1
- 0
server/tests/src/com/vaadin/tests/server/TestClassesSerializable.java View File

@@ -63,6 +63,7 @@ public class TestClassesSerializable extends TestCase {
"com\\.vaadin\\.sass.*", //
"com\\.vaadin\\.testbench.*", //
"com\\.vaadin\\.util\\.CurrentInstance\\$1", //
"com\\.vaadin\\.server\\.JsonCodec\\$1", //
"com\\.vaadin\\.server\\.communication\\.PushConnection", //
"com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection", //
"com\\.vaadin\\.util\\.ConnectorHelper", //

Loading…
Cancel
Save