Skip to content

Commit 3de12be

Browse files
cpovirkGoogle Java Core Libraries
authored and
Google Java Core Libraries
committedMay 26, 2023
Under J2CL+GWT, remove keyType() and valueType() from the Enum*BiMap classes.
Previously, the methods were present but sometimes returned `null` Under J2CL. And soon, J2CL may drop support for the reflective enum-related APIs that they depend on. `guava-gwt` is used by both GWT and J2CL users, so we have to keep our code buildable against both. RELNOTES=`collect`: Removed the `Enum*BiMap` classes's `keyType()` and `valueType()` methods from `guava-gwt` to prepare for the removal of reflective enum-related APIs from J2CL. If this causes you problems as a GWT user, let us know. PiperOrigin-RevId: 535711221
1 parent 09db2c2 commit 3de12be

File tree

12 files changed

+144
-66
lines changed

12 files changed

+144
-66
lines changed
 

‎android/guava-tests/test/com/google/common/collect/EnumBiMapTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,13 @@ public void testEnumBiMapConstructor() {
183183
assertEquals(bimap3, emptyBimap);
184184
}
185185

186+
@GwtIncompatible // keyType
186187
public void testKeyType() {
187188
EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class);
188189
assertEquals(Currency.class, bimap.keyType());
189190
}
190191

192+
@GwtIncompatible // valueType
191193
public void testValueType() {
192194
EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class);
193195
assertEquals(Country.class, bimap.valueType());

‎android/guava-tests/test/com/google/common/collect/EnumHashBiMapTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public void testEnumBiMapConstructor() {
197197
assertEquals(bimap3, emptyBimap);
198198
}
199199

200+
@GwtIncompatible // keyType
200201
public void testKeyType() {
201202
EnumHashBiMap<Currency, String> bimap = EnumHashBiMap.create(Currency.class);
202203
assertEquals(Currency.class, bimap.keyType());

‎android/guava/src/com/google/common/collect/EnumBiMap.java

+41-21
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
21+
import static com.google.common.collect.Platform.getDeclaringClassOrObjectForJ2cl;
2122

2223
import com.google.common.annotations.GwtCompatible;
2324
import com.google.common.annotations.GwtIncompatible;
@@ -42,8 +43,22 @@
4243
@J2ktIncompatible
4344
@ElementTypesAreNonnullByDefault
4445
public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>> extends AbstractBiMap<K, V> {
45-
private transient Class<K> keyType;
46-
private transient Class<V> valueType;
46+
/*
47+
* J2CL's EnumMap does not need the Class instance, so we can use Object.class instead. (Or we
48+
* could use null, but that messes with our nullness checking, including under J2KT. We could
49+
* probably work around it by changing how we annotate the J2CL EnumMap, but that's probably more
50+
* trouble than just using Object.class.)
51+
*
52+
* Then we declare the getters for these fields as @GwtIncompatible so that no one can try to use
53+
* them under J2CL—or, as an unfortunate side effect, under GWT. We do still give the fields
54+
* themselves their proper values under GWT, since GWT's EnumMap does need the Class instance.
55+
*
56+
* Note that sometimes these fields *do* have correct values under J2CL: They will if the caller
57+
* calls `create(Foo.class)`, rather than `create(map)`. That's fine; we just shouldn't rely on
58+
* it.
59+
*/
60+
transient Class<K> keyTypeOrObjectUnderJ2cl;
61+
transient Class<V> valueTypeOrObjectUnderJ2cl;
4762

4863
/**
4964
* Returns a new, empty {@code EnumBiMap} using the specified key and value types.
@@ -66,44 +81,48 @@ public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(
6681
* mappings
6782
*/
6883
public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(Map<K, V> map) {
69-
EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
84+
EnumBiMap<K, V> bimap =
85+
create(inferKeyTypeOrObjectUnderJ2cl(map), inferValueTypeOrObjectUnderJ2cl(map));
7086
bimap.putAll(map);
7187
return bimap;
7288
}
7389

74-
private EnumBiMap(Class<K> keyType, Class<V> valueType) {
75-
super(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
76-
this.keyType = keyType;
77-
this.valueType = valueType;
90+
private EnumBiMap(Class<K> keyTypeOrObjectUnderJ2cl, Class<V> valueTypeOrObjectUnderJ2cl) {
91+
super(
92+
new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new EnumMap<V, K>(valueTypeOrObjectUnderJ2cl));
93+
this.keyTypeOrObjectUnderJ2cl = keyTypeOrObjectUnderJ2cl;
94+
this.valueTypeOrObjectUnderJ2cl = valueTypeOrObjectUnderJ2cl;
7895
}
7996

80-
static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
97+
static <K extends Enum<K>> Class<K> inferKeyTypeOrObjectUnderJ2cl(Map<K, ?> map) {
8198
if (map instanceof EnumBiMap) {
82-
return ((EnumBiMap<K, ?>) map).keyType();
99+
return ((EnumBiMap<K, ?>) map).keyTypeOrObjectUnderJ2cl;
83100
}
84101
if (map instanceof EnumHashBiMap) {
85-
return ((EnumHashBiMap<K, ?>) map).keyType();
102+
return ((EnumHashBiMap<K, ?>) map).keyTypeOrObjectUnderJ2cl;
86103
}
87104
checkArgument(!map.isEmpty());
88-
return map.keySet().iterator().next().getDeclaringClass();
105+
return getDeclaringClassOrObjectForJ2cl(map.keySet().iterator().next());
89106
}
90107

91-
private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
108+
private static <V extends Enum<V>> Class<V> inferValueTypeOrObjectUnderJ2cl(Map<?, V> map) {
92109
if (map instanceof EnumBiMap) {
93-
return ((EnumBiMap<?, V>) map).valueType;
110+
return ((EnumBiMap<?, V>) map).valueTypeOrObjectUnderJ2cl;
94111
}
95112
checkArgument(!map.isEmpty());
96-
return map.values().iterator().next().getDeclaringClass();
113+
return getDeclaringClassOrObjectForJ2cl(map.values().iterator().next());
97114
}
98115

99116
/** Returns the associated key type. */
117+
@GwtIncompatible
100118
public Class<K> keyType() {
101-
return keyType;
119+
return keyTypeOrObjectUnderJ2cl;
102120
}
103121

104122
/** Returns the associated value type. */
123+
@GwtIncompatible
105124
public Class<V> valueType() {
106-
return valueType;
125+
return valueTypeOrObjectUnderJ2cl;
107126
}
108127

109128
@Override
@@ -123,18 +142,19 @@ V checkValue(V value) {
123142
@GwtIncompatible // java.io.ObjectOutputStream
124143
private void writeObject(ObjectOutputStream stream) throws IOException {
125144
stream.defaultWriteObject();
126-
stream.writeObject(keyType);
127-
stream.writeObject(valueType);
145+
stream.writeObject(keyTypeOrObjectUnderJ2cl);
146+
stream.writeObject(valueTypeOrObjectUnderJ2cl);
128147
Serialization.writeMap(this, stream);
129148
}
130149

131150
@SuppressWarnings("unchecked") // reading fields populated by writeObject
132151
@GwtIncompatible // java.io.ObjectInputStream
133152
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
134153
stream.defaultReadObject();
135-
keyType = (Class<K>) stream.readObject();
136-
valueType = (Class<V>) stream.readObject();
137-
setDelegates(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
154+
keyTypeOrObjectUnderJ2cl = (Class<K>) stream.readObject();
155+
valueTypeOrObjectUnderJ2cl = (Class<V>) stream.readObject();
156+
setDelegates(
157+
new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new EnumMap<V, K>(valueTypeOrObjectUnderJ2cl));
138158
Serialization.populateMap(this, stream);
139159
}
140160

‎android/guava/src/com/google/common/collect/EnumHashBiMap.java

+15-11
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
@ElementTypesAreNonnullByDefault
4848
public final class EnumHashBiMap<K extends Enum<K>, V extends @Nullable Object>
4949
extends AbstractBiMap<K, V> {
50-
private transient Class<K> keyType;
50+
transient Class<K> keyTypeOrObjectUnderJ2cl;
5151

5252
/**
5353
* Returns a new, empty {@code EnumHashBiMap} using the specified key type.
@@ -71,16 +71,15 @@ public final class EnumHashBiMap<K extends Enum<K>, V extends @Nullable Object>
7171
*/
7272
public static <K extends Enum<K>, V extends @Nullable Object> EnumHashBiMap<K, V> create(
7373
Map<K, ? extends V> map) {
74-
EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map));
74+
EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyTypeOrObjectUnderJ2cl(map));
7575
bimap.putAll(map);
7676
return bimap;
7777
}
7878

7979
private EnumHashBiMap(Class<K> keyType) {
80-
super(
81-
new EnumMap<K, V>(keyType),
82-
Maps.<V, K>newHashMapWithExpectedSize(keyType.getEnumConstants().length));
83-
this.keyType = keyType;
80+
super(new EnumMap<K, V>(keyType), new HashMap<V, K>());
81+
// TODO: cpovirk - Pre-size the HashMap based on the number of enum values?
82+
this.keyTypeOrObjectUnderJ2cl = keyType;
8483
}
8584

8685
// Overriding these 3 methods to show that values may be null (but not keys)
@@ -109,8 +108,9 @@ public V forcePut(K key, @ParametricNullness V value) {
109108
}
110109

111110
/** Returns the associated key type. */
111+
@GwtIncompatible
112112
public Class<K> keyType() {
113-
return keyType;
113+
return keyTypeOrObjectUnderJ2cl;
114114
}
115115

116116
/**
@@ -120,17 +120,21 @@ public Class<K> keyType() {
120120
@GwtIncompatible // java.io.ObjectOutputStream
121121
private void writeObject(ObjectOutputStream stream) throws IOException {
122122
stream.defaultWriteObject();
123-
stream.writeObject(keyType);
123+
stream.writeObject(keyTypeOrObjectUnderJ2cl);
124124
Serialization.writeMap(this, stream);
125125
}
126126

127127
@SuppressWarnings("unchecked") // reading field populated by writeObject
128128
@GwtIncompatible // java.io.ObjectInputStream
129129
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
130130
stream.defaultReadObject();
131-
keyType = (Class<K>) stream.readObject();
132-
setDelegates(
133-
new EnumMap<K, V>(keyType), new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
131+
keyTypeOrObjectUnderJ2cl = (Class<K>) stream.readObject();
132+
/*
133+
* TODO: cpovirk - Pre-size the HashMap based on the number of enum values? (But *not* based on
134+
* the number of entries in the map, as that makes it easy for hostile inputs to trigger lots of
135+
* allocation—not that any program should be deserializing hostile inputs to begin with!)
136+
*/
137+
setDelegates(new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new HashMap<V, K>());
134138
Serialization.populateMap(this, stream);
135139
}
136140

‎android/guava/src/com/google/common/collect/Platform.java

+4
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ static MapMaker tryWeakKeys(MapMaker mapMaker) {
117117
return mapMaker.weakKeys();
118118
}
119119

120+
static <E extends Enum<E>> Class<E> getDeclaringClassOrObjectForJ2cl(E e) {
121+
return e.getDeclaringClass();
122+
}
123+
120124
static int reduceIterationsIfGwt(int iterations) {
121125
return iterations;
122126
}

‎guava-gwt/src-super/com/google/common/collect/super/com/google/common/collect/Platform.java

+15-2
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
import java.util.Map;
2222
import java.util.Set;
2323
import java.util.concurrent.ConcurrentHashMap;
24+
import jsinterop.annotations.JsMethod;
2425
import jsinterop.annotations.JsPackage;
2526
import jsinterop.annotations.JsProperty;
2627
import jsinterop.annotations.JsType;
28+
import org.checkerframework.checker.nullness.qual.Nullable;
2729

2830
/**
2931
* Minimal GWT emulation of {@code com.google.common.collect.Platform}.
3032
*
31-
* <p><strong>This .java file should never be consumed by javac.</strong>
32-
*
3333
* @author Hayward Chan
3434
*/
3535
final class Platform {
@@ -96,6 +96,19 @@ static MapMaker tryWeakKeys(MapMaker mapMaker) {
9696
return mapMaker;
9797
}
9898

99+
static <E extends Enum<E>> Class<E> getDeclaringClassOrObjectForJ2cl(E e) {
100+
Class<E> classOrNull = getDeclaringClassOrNullForJ2cl(e);
101+
@SuppressWarnings("unchecked")
102+
Class<E> result = classOrNull == null ? (Class<E>) (Class<?>) Object.class : classOrNull;
103+
return result;
104+
}
105+
106+
@JsMethod
107+
private static native <E extends Enum<E>> @Nullable Class<E> getDeclaringClassOrNullForJ2cl(
108+
E e) /*-{
109+
return e.@java.lang.Enum::getDeclaringClass()();
110+
}-*/;
111+
99112
static int reduceIterationsIfGwt(int iterations) {
100113
return iterations / 10;
101114
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Platform.getDeclaringClassOrNullForJ2cl = function(e) {
2+
return null;
3+
}

‎guava-tests/test/com/google/common/collect/EnumBiMapTest.java

+2
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,13 @@ public void testEnumBiMapConstructor() {
183183
assertEquals(bimap3, emptyBimap);
184184
}
185185

186+
@GwtIncompatible // keyType
186187
public void testKeyType() {
187188
EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class);
188189
assertEquals(Currency.class, bimap.keyType());
189190
}
190191

192+
@GwtIncompatible // valueType
191193
public void testValueType() {
192194
EnumBiMap<Currency, Country> bimap = EnumBiMap.create(Currency.class, Country.class);
193195
assertEquals(Country.class, bimap.valueType());

‎guava-tests/test/com/google/common/collect/EnumHashBiMapTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ public void testEnumBiMapConstructor() {
197197
assertEquals(bimap3, emptyBimap);
198198
}
199199

200+
@GwtIncompatible // keyType
200201
public void testKeyType() {
201202
EnumHashBiMap<Currency, String> bimap = EnumHashBiMap.create(Currency.class);
202203
assertEquals(Currency.class, bimap.keyType());

‎guava/src/com/google/common/collect/EnumBiMap.java

+41-21
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import static com.google.common.base.Preconditions.checkArgument;
2020
import static com.google.common.base.Preconditions.checkNotNull;
21+
import static com.google.common.collect.Platform.getDeclaringClassOrObjectForJ2cl;
2122

2223
import com.google.common.annotations.GwtCompatible;
2324
import com.google.common.annotations.GwtIncompatible;
@@ -42,8 +43,22 @@
4243
@J2ktIncompatible
4344
@ElementTypesAreNonnullByDefault
4445
public final class EnumBiMap<K extends Enum<K>, V extends Enum<V>> extends AbstractBiMap<K, V> {
45-
private transient Class<K> keyType;
46-
private transient Class<V> valueType;
46+
/*
47+
* J2CL's EnumMap does not need the Class instance, so we can use Object.class instead. (Or we
48+
* could use null, but that messes with our nullness checking, including under J2KT. We could
49+
* probably work around it by changing how we annotate the J2CL EnumMap, but that's probably more
50+
* trouble than just using Object.class.)
51+
*
52+
* Then we declare the getters for these fields as @GwtIncompatible so that no one can try to use
53+
* them under J2CL—or, as an unfortunate side effect, under GWT. We do still give the fields
54+
* themselves their proper values under GWT, since GWT's EnumMap does need the Class instance.
55+
*
56+
* Note that sometimes these fields *do* have correct values under J2CL: They will if the caller
57+
* calls `create(Foo.class)`, rather than `create(map)`. That's fine; we just shouldn't rely on
58+
* it.
59+
*/
60+
transient Class<K> keyTypeOrObjectUnderJ2cl;
61+
transient Class<V> valueTypeOrObjectUnderJ2cl;
4762

4863
/**
4964
* Returns a new, empty {@code EnumBiMap} using the specified key and value types.
@@ -66,44 +81,48 @@ public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(
6681
* mappings
6782
*/
6883
public static <K extends Enum<K>, V extends Enum<V>> EnumBiMap<K, V> create(Map<K, V> map) {
69-
EnumBiMap<K, V> bimap = create(inferKeyType(map), inferValueType(map));
84+
EnumBiMap<K, V> bimap =
85+
create(inferKeyTypeOrObjectUnderJ2cl(map), inferValueTypeOrObjectUnderJ2cl(map));
7086
bimap.putAll(map);
7187
return bimap;
7288
}
7389

74-
private EnumBiMap(Class<K> keyType, Class<V> valueType) {
75-
super(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
76-
this.keyType = keyType;
77-
this.valueType = valueType;
90+
private EnumBiMap(Class<K> keyTypeOrObjectUnderJ2cl, Class<V> valueTypeOrObjectUnderJ2cl) {
91+
super(
92+
new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new EnumMap<V, K>(valueTypeOrObjectUnderJ2cl));
93+
this.keyTypeOrObjectUnderJ2cl = keyTypeOrObjectUnderJ2cl;
94+
this.valueTypeOrObjectUnderJ2cl = valueTypeOrObjectUnderJ2cl;
7895
}
7996

80-
static <K extends Enum<K>> Class<K> inferKeyType(Map<K, ?> map) {
97+
static <K extends Enum<K>> Class<K> inferKeyTypeOrObjectUnderJ2cl(Map<K, ?> map) {
8198
if (map instanceof EnumBiMap) {
82-
return ((EnumBiMap<K, ?>) map).keyType();
99+
return ((EnumBiMap<K, ?>) map).keyTypeOrObjectUnderJ2cl;
83100
}
84101
if (map instanceof EnumHashBiMap) {
85-
return ((EnumHashBiMap<K, ?>) map).keyType();
102+
return ((EnumHashBiMap<K, ?>) map).keyTypeOrObjectUnderJ2cl;
86103
}
87104
checkArgument(!map.isEmpty());
88-
return map.keySet().iterator().next().getDeclaringClass();
105+
return getDeclaringClassOrObjectForJ2cl(map.keySet().iterator().next());
89106
}
90107

91-
private static <V extends Enum<V>> Class<V> inferValueType(Map<?, V> map) {
108+
private static <V extends Enum<V>> Class<V> inferValueTypeOrObjectUnderJ2cl(Map<?, V> map) {
92109
if (map instanceof EnumBiMap) {
93-
return ((EnumBiMap<?, V>) map).valueType;
110+
return ((EnumBiMap<?, V>) map).valueTypeOrObjectUnderJ2cl;
94111
}
95112
checkArgument(!map.isEmpty());
96-
return map.values().iterator().next().getDeclaringClass();
113+
return getDeclaringClassOrObjectForJ2cl(map.values().iterator().next());
97114
}
98115

99116
/** Returns the associated key type. */
117+
@GwtIncompatible
100118
public Class<K> keyType() {
101-
return keyType;
119+
return keyTypeOrObjectUnderJ2cl;
102120
}
103121

104122
/** Returns the associated value type. */
123+
@GwtIncompatible
105124
public Class<V> valueType() {
106-
return valueType;
125+
return valueTypeOrObjectUnderJ2cl;
107126
}
108127

109128
@Override
@@ -123,18 +142,19 @@ V checkValue(V value) {
123142
@GwtIncompatible // java.io.ObjectOutputStream
124143
private void writeObject(ObjectOutputStream stream) throws IOException {
125144
stream.defaultWriteObject();
126-
stream.writeObject(keyType);
127-
stream.writeObject(valueType);
145+
stream.writeObject(keyTypeOrObjectUnderJ2cl);
146+
stream.writeObject(valueTypeOrObjectUnderJ2cl);
128147
Serialization.writeMap(this, stream);
129148
}
130149

131150
@SuppressWarnings("unchecked") // reading fields populated by writeObject
132151
@GwtIncompatible // java.io.ObjectInputStream
133152
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
134153
stream.defaultReadObject();
135-
keyType = (Class<K>) stream.readObject();
136-
valueType = (Class<V>) stream.readObject();
137-
setDelegates(new EnumMap<K, V>(keyType), new EnumMap<V, K>(valueType));
154+
keyTypeOrObjectUnderJ2cl = (Class<K>) stream.readObject();
155+
valueTypeOrObjectUnderJ2cl = (Class<V>) stream.readObject();
156+
setDelegates(
157+
new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new EnumMap<V, K>(valueTypeOrObjectUnderJ2cl));
138158
Serialization.populateMap(this, stream);
139159
}
140160

‎guava/src/com/google/common/collect/EnumHashBiMap.java

+15-11
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
@ElementTypesAreNonnullByDefault
4848
public final class EnumHashBiMap<K extends Enum<K>, V extends @Nullable Object>
4949
extends AbstractBiMap<K, V> {
50-
private transient Class<K> keyType;
50+
transient Class<K> keyTypeOrObjectUnderJ2cl;
5151

5252
/**
5353
* Returns a new, empty {@code EnumHashBiMap} using the specified key type.
@@ -71,16 +71,15 @@ public final class EnumHashBiMap<K extends Enum<K>, V extends @Nullable Object>
7171
*/
7272
public static <K extends Enum<K>, V extends @Nullable Object> EnumHashBiMap<K, V> create(
7373
Map<K, ? extends V> map) {
74-
EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map));
74+
EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyTypeOrObjectUnderJ2cl(map));
7575
bimap.putAll(map);
7676
return bimap;
7777
}
7878

7979
private EnumHashBiMap(Class<K> keyType) {
80-
super(
81-
new EnumMap<K, V>(keyType),
82-
Maps.<V, K>newHashMapWithExpectedSize(keyType.getEnumConstants().length));
83-
this.keyType = keyType;
80+
super(new EnumMap<K, V>(keyType), new HashMap<V, K>());
81+
// TODO: cpovirk - Pre-size the HashMap based on the number of enum values?
82+
this.keyTypeOrObjectUnderJ2cl = keyType;
8483
}
8584

8685
// Overriding these 3 methods to show that values may be null (but not keys)
@@ -109,8 +108,9 @@ public V forcePut(K key, @ParametricNullness V value) {
109108
}
110109

111110
/** Returns the associated key type. */
111+
@GwtIncompatible
112112
public Class<K> keyType() {
113-
return keyType;
113+
return keyTypeOrObjectUnderJ2cl;
114114
}
115115

116116
/**
@@ -120,17 +120,21 @@ public Class<K> keyType() {
120120
@GwtIncompatible // java.io.ObjectOutputStream
121121
private void writeObject(ObjectOutputStream stream) throws IOException {
122122
stream.defaultWriteObject();
123-
stream.writeObject(keyType);
123+
stream.writeObject(keyTypeOrObjectUnderJ2cl);
124124
Serialization.writeMap(this, stream);
125125
}
126126

127127
@SuppressWarnings("unchecked") // reading field populated by writeObject
128128
@GwtIncompatible // java.io.ObjectInputStream
129129
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
130130
stream.defaultReadObject();
131-
keyType = (Class<K>) stream.readObject();
132-
setDelegates(
133-
new EnumMap<K, V>(keyType), new HashMap<V, K>(keyType.getEnumConstants().length * 3 / 2));
131+
keyTypeOrObjectUnderJ2cl = (Class<K>) stream.readObject();
132+
/*
133+
* TODO: cpovirk - Pre-size the HashMap based on the number of enum values? (But *not* based on
134+
* the number of entries in the map, as that makes it easy for hostile inputs to trigger lots of
135+
* allocation—not that any program should be deserializing hostile inputs to begin with!)
136+
*/
137+
setDelegates(new EnumMap<K, V>(keyTypeOrObjectUnderJ2cl), new HashMap<V, K>());
134138
Serialization.populateMap(this, stream);
135139
}
136140

‎guava/src/com/google/common/collect/Platform.java

+4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ static MapMaker tryWeakKeys(MapMaker mapMaker) {
126126
return mapMaker.weakKeys();
127127
}
128128

129+
static <E extends Enum<E>> Class<E> getDeclaringClassOrObjectForJ2cl(E e) {
130+
return e.getDeclaringClass();
131+
}
132+
129133
static int reduceIterationsIfGwt(int iterations) {
130134
return iterations;
131135
}

0 commit comments

Comments
 (0)
Please sign in to comment.