18
18
19
19
import static com .google .common .base .Preconditions .checkArgument ;
20
20
import static com .google .common .base .Preconditions .checkNotNull ;
21
+ import static com .google .common .collect .Platform .getDeclaringClassOrObjectForJ2cl ;
21
22
22
23
import com .google .common .annotations .GwtCompatible ;
23
24
import com .google .common .annotations .GwtIncompatible ;
42
43
@ J2ktIncompatible
43
44
@ ElementTypesAreNonnullByDefault
44
45
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 ;
47
62
48
63
/**
49
64
* 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(
66
81
* mappings
67
82
*/
68
83
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 ));
70
86
bimap .putAll (map );
71
87
return bimap ;
72
88
}
73
89
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 ;
78
95
}
79
96
80
- static <K extends Enum <K >> Class <K > inferKeyType (Map <K , ?> map ) {
97
+ static <K extends Enum <K >> Class <K > inferKeyTypeOrObjectUnderJ2cl (Map <K , ?> map ) {
81
98
if (map instanceof EnumBiMap ) {
82
- return ((EnumBiMap <K , ?>) map ).keyType () ;
99
+ return ((EnumBiMap <K , ?>) map ).keyTypeOrObjectUnderJ2cl ;
83
100
}
84
101
if (map instanceof EnumHashBiMap ) {
85
- return ((EnumHashBiMap <K , ?>) map ).keyType () ;
102
+ return ((EnumHashBiMap <K , ?>) map ).keyTypeOrObjectUnderJ2cl ;
86
103
}
87
104
checkArgument (!map .isEmpty ());
88
- return map .keySet ().iterator ().next (). getDeclaringClass ( );
105
+ return getDeclaringClassOrObjectForJ2cl ( map .keySet ().iterator ().next ());
89
106
}
90
107
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 ) {
92
109
if (map instanceof EnumBiMap ) {
93
- return ((EnumBiMap <?, V >) map ).valueType ;
110
+ return ((EnumBiMap <?, V >) map ).valueTypeOrObjectUnderJ2cl ;
94
111
}
95
112
checkArgument (!map .isEmpty ());
96
- return map .values ().iterator ().next (). getDeclaringClass ( );
113
+ return getDeclaringClassOrObjectForJ2cl ( map .values ().iterator ().next ());
97
114
}
98
115
99
116
/** Returns the associated key type. */
117
+ @ GwtIncompatible
100
118
public Class <K > keyType () {
101
- return keyType ;
119
+ return keyTypeOrObjectUnderJ2cl ;
102
120
}
103
121
104
122
/** Returns the associated value type. */
123
+ @ GwtIncompatible
105
124
public Class <V > valueType () {
106
- return valueType ;
125
+ return valueTypeOrObjectUnderJ2cl ;
107
126
}
108
127
109
128
@ Override
@@ -123,18 +142,19 @@ V checkValue(V value) {
123
142
@ GwtIncompatible // java.io.ObjectOutputStream
124
143
private void writeObject (ObjectOutputStream stream ) throws IOException {
125
144
stream .defaultWriteObject ();
126
- stream .writeObject (keyType );
127
- stream .writeObject (valueType );
145
+ stream .writeObject (keyTypeOrObjectUnderJ2cl );
146
+ stream .writeObject (valueTypeOrObjectUnderJ2cl );
128
147
Serialization .writeMap (this , stream );
129
148
}
130
149
131
150
@ SuppressWarnings ("unchecked" ) // reading fields populated by writeObject
132
151
@ GwtIncompatible // java.io.ObjectInputStream
133
152
private void readObject (ObjectInputStream stream ) throws IOException , ClassNotFoundException {
134
153
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 ));
138
158
Serialization .populateMap (this , stream );
139
159
}
140
160
0 commit comments