From 852cd720590c120f23f033f53540a73ac64c4234 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Sat, 26 Nov 2011 15:36:08 +0000 Subject: [PATCH] Don't allocate a whole bunch of objects each time we deserialize a map key. This saves 20% on bug 375's benchmark. The fix here is quite distasteful; I'm adding an ugly backdoor API for MapTypeAdapterFactory to fiddle with the internal bits of JsonReader. I'd like to revisit this sooner or later, but for now I'll take the speedup. --- .../internal/JsonReaderInternalAccess.java | 32 +++++++++++++++++++ .../internal/bind/MapTypeAdapterFactory.java | 5 +-- .../com/google/gson/stream/JsonReader.java | 15 +++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100644 gson/src/main/java/com/google/gson/internal/JsonReaderInternalAccess.java diff --git a/gson/src/main/java/com/google/gson/internal/JsonReaderInternalAccess.java b/gson/src/main/java/com/google/gson/internal/JsonReaderInternalAccess.java new file mode 100644 index 00000000..bbd47204 --- /dev/null +++ b/gson/src/main/java/com/google/gson/internal/JsonReaderInternalAccess.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 Google Inc. + * + * 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.google.gson.internal; + +import com.google.gson.stream.JsonReader; +import java.io.IOException; + +/** + * Internal-only APIs of JsonReader available only to other classes in Gson. + */ +public abstract class JsonReaderInternalAccess { + public static JsonReaderInternalAccess INSTANCE; + + /** + * Changes the type of the current property name token to a string value. + */ + public abstract void promoteNameToValue(JsonReader reader) throws IOException; +} diff --git a/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java b/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java index 5e0da20d..88102474 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java +++ b/gson/src/main/java/com/google/gson/internal/bind/MapTypeAdapterFactory.java @@ -23,6 +23,7 @@ import com.google.gson.JsonSyntaxException; import com.google.gson.TypeAdapter; import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.ConstructorConstructor; +import com.google.gson.internal.JsonReaderInternalAccess; import com.google.gson.internal.ObjectConstructor; import com.google.gson.internal.Streams; import com.google.gson.reflect.TypeToken; @@ -180,8 +181,8 @@ public final class MapTypeAdapterFactory implements TypeAdapter.Factory { } else { reader.beginObject(); while (reader.hasNext()) { - String keyString = reader.nextName(); - K key = keyTypeAdapter.fromJsonElement(new JsonPrimitive(keyString)); + JsonReaderInternalAccess.INSTANCE.promoteNameToValue(reader); + K key = keyTypeAdapter.read(reader); V value = valueTypeAdapter.read(reader); V replaced = map.put(key, value); if (replaced != null) { diff --git a/gson/src/main/java/com/google/gson/stream/JsonReader.java b/gson/src/main/java/com/google/gson/stream/JsonReader.java index 4f366d0a..9b691397 100644 --- a/gson/src/main/java/com/google/gson/stream/JsonReader.java +++ b/gson/src/main/java/com/google/gson/stream/JsonReader.java @@ -16,6 +16,7 @@ package com.google.gson.stream; +import com.google.gson.internal.JsonReaderInternalAccess; import java.io.Closeable; import java.io.EOFException; import java.io.IOException; @@ -1167,4 +1168,18 @@ public class JsonReader implements Closeable { snippet.append(buffer, pos, afterPos); return snippet; } + + static { + JsonReaderInternalAccess.INSTANCE = new JsonReaderInternalAccess() { + @Override public void promoteNameToValue(JsonReader reader) throws IOException { + reader.quickPeek(); + if (reader.token != JsonToken.NAME) { + throw new IllegalStateException("Expected a name but was " + reader.peek()); + } + reader.value = reader.name; + reader.name = null; + reader.token = JsonToken.STRING; + } + }; + } }