Support null values in StringMap

This commit is contained in:
Jesse Wilson 2012-03-11 15:19:01 +00:00
parent ad3489f557
commit 751c69c655
3 changed files with 31 additions and 16 deletions

View File

@ -29,7 +29,8 @@ import java.util.Set;
/**
* A map of strings to values. Like LinkedHashMap, this map's iteration order is
* well defined: it is the order that elements were inserted into the map.
* well defined: it is the order that elements were inserted into the map. This
* map does not support null keys.
*
* <p>This implementation was derived from Android 4.0's LinkedHashMap.
*/
@ -98,32 +99,33 @@ public final class StringMap<K, V> extends AbstractMap<K, V> {
}
@Override public boolean containsKey(Object key) {
return get(key) != null;
return getEntry(key) != null;
}
@Override public V get(Object key) {
LinkedEntry<K, V> entry = getEntry(key);
return entry != null ? entry.value : null;
}
private LinkedEntry<K, V> getEntry(Object key) {
if (key == null) {
return null;
}
// Doug Lea's supplemental secondaryHash function (inlined)
int hash = key.hashCode();
hash ^= (hash >>> 20) ^ (hash >>> 12);
hash ^= (hash >>> 7) ^ (hash >>> 4);
int hash = secondaryHash(key.hashCode());
LinkedEntry<K, V>[] tab = table;
for (LinkedEntry<K, V> e = tab[hash & (tab.length - 1)]; e != null; e = e.next) {
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
return e;
}
}
return null;
}
@Override public V put(K key, V value) {
if (key == null || value == null) {
throw new IllegalArgumentException();
if (key == null) {
throw new NullPointerException("key == null");
}
int hash = secondaryHash(key.hashCode());
@ -311,9 +313,6 @@ public final class StringMap<K, V> extends AbstractMap<K, V> {
}
public final V setValue(V value) {
if (value == null) {
throw new IllegalArgumentException();
}
V oldValue = this.value;
this.value = value;
return oldValue;
@ -324,7 +323,9 @@ public final class StringMap<K, V> extends AbstractMap<K, V> {
return false;
}
Entry<?, ?> e = (Entry<?, ?>) o;
return key.equals(e.getKey()) && value.equals(e.getValue());
Object eValue = e.getValue();
return key.equals(e.getKey())
&& (value == null ? eValue == null : value.equals(eValue));
}
@Override public final int hashCode() {
@ -341,7 +342,7 @@ public final class StringMap<K, V> extends AbstractMap<K, V> {
* exists; otherwise, returns does nothing and returns false.
*/
private boolean removeMapping(Object key, Object value) {
if (key == null || value == null) {
if (key == null) {
return false;
}
@ -350,7 +351,7 @@ public final class StringMap<K, V> extends AbstractMap<K, V> {
int index = hash & (tab.length - 1);
for (LinkedEntry<K, V> e = tab[index], prev = null; e != null; prev = e, e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
if (!value.equals(e.value)) {
if (value == null ? e.value != null : !value.equals(e.value)) {
return false; // Map has wrong value for key
}
if (prev == null) {

View File

@ -63,6 +63,7 @@ public final class ObjectTypeAdapter extends TypeAdapter<Object> {
return list;
case BEGIN_OBJECT:
// TODO: string map doesn't support null values
Map<String, Object> map = new StringMap<String, Object>();
in.beginObject();
while (in.hasNext()) {

View File

@ -18,6 +18,7 @@ package com.google.gson;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import junit.framework.TestCase;
@ -37,6 +38,18 @@ public final class ObjectTypeAdapterTest extends TestCase {
Object object = new RuntimeType();
assertEquals("{'a':5,'b':[1,2,null]}", adapter.toJson(object).replace("\"", "'"));
}
public void testSerializeNullValue() throws Exception {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("a", null);
assertEquals("{'a':null}", adapter.toJson(map).replace('"', '\''));
}
public void testDeserializeNullValue() throws Exception {
Map<String, Object> map = new LinkedHashMap<String, Object>();
map.put("a", null);
assertEquals(map, adapter.fromJson("{\"a\":null}"));
}
public void testSerializeObject() throws Exception {
assertEquals("{}", adapter.toJson(new Object()));