Skip to content

Commit dc0905b

Browse files
committed
Replace EnumResolver usage for deserialization with specialized map
1 parent 88059ce commit dc0905b

File tree

3 files changed

+110
-81
lines changed

3 files changed

+110
-81
lines changed

src/main/java/com/fasterxml/jackson/databind/deser/std/EnumDeserializer.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
1111
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
1212
import com.fasterxml.jackson.databind.util.ClassUtil;
13+
import com.fasterxml.jackson.databind.util.CompactStringObjectMap;
1314
import com.fasterxml.jackson.databind.util.EnumResolver;
1415

1516
/**
@@ -22,12 +23,21 @@ public class EnumDeserializer
2223
{
2324
private static final long serialVersionUID = 1L;
2425

25-
protected final EnumResolver _resolver;
26-
26+
/**
27+
* @since 2.6
28+
*/
29+
protected final CompactStringObjectMap _enumLookup;
30+
31+
/**
32+
* @since 2.6
33+
*/
34+
protected Object[] _enumsByIndex;
35+
2736
public EnumDeserializer(EnumResolver res)
2837
{
29-
super(Enum.class);
30-
_resolver = res;
38+
super(res.getEnumClass());
39+
_enumLookup = res.constructLookup();
40+
_enumsByIndex = res.getRawEnums();
3141
}
3242

3343
/**
@@ -69,7 +79,7 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
6979
// Usually should just get string value:
7080
if (curr == JsonToken.VALUE_STRING || curr == JsonToken.FIELD_NAME) {
7181
String name = p.getText();
72-
Enum<?> result = _resolver.findEnum(name);
82+
Object result = _enumLookup.find(name);
7383
if (result == null) {
7484
return _deserializeAltString(p, ctxt, name);
7585
}
@@ -81,17 +91,19 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
8191
_checkFailOnNumber(ctxt);
8292

8393
int index = p.getIntValue();
84-
Enum<?> result = _resolver.getEnum(index);
85-
if (result == null && !ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
86-
throw ctxt.weirdNumberException(Integer.valueOf(index), _resolver.getEnumClass(),
87-
"index value outside legal index range [0.."+_resolver.lastValidIndex()+"]");
94+
if (index >= 0 && index <= _enumsByIndex.length) {
95+
return _enumsByIndex[index];
8896
}
89-
return result;
97+
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
98+
throw ctxt.weirdNumberException(Integer.valueOf(index), _enumClass(),
99+
"index value outside legal index range [0.."+(_enumsByIndex.length-1)+"]");
100+
}
101+
return null;
90102
}
91103
return _deserializeOther(p, ctxt);
92104
}
93105

94-
private final Enum<?> _deserializeAltString(JsonParser p, DeserializationContext ctxt,
106+
private final Object _deserializeAltString(JsonParser p, DeserializationContext ctxt,
95107
String name) throws IOException
96108
{
97109
name = name.trim();
@@ -106,18 +118,17 @@ private final Enum<?> _deserializeAltString(JsonParser p, DeserializationContext
106118
try {
107119
int ix = Integer.parseInt(name);
108120
_checkFailOnNumber(ctxt);
109-
Enum<?> result = _resolver.getEnum(ix);
110-
if (result != null) {
111-
return result;
121+
if (ix >= 0 && ix <= _enumsByIndex.length) {
122+
return _enumsByIndex[ix];
112123
}
113124
} catch (NumberFormatException e) {
114125
// fine, ignore, was not an integer
115126
}
116127
}
117128
}
118129
if (!ctxt.isEnabled(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_AS_NULL)) {
119-
throw ctxt.weirdStringException(name, _resolver.getEnumClass(),
120-
"value not one of declared Enum instance names: "+_resolver.getEnums());
130+
throw ctxt.weirdStringException(name, _enumClass(),
131+
"value not one of declared Enum instance names: "+_enumLookup.keys());
121132
}
122133
return null;
123134
}
@@ -132,11 +143,11 @@ protected Object _deserializeOther(JsonParser p, DeserializationContext ctxt) th
132143
curr = p.nextToken();
133144
if (curr != JsonToken.END_ARRAY) {
134145
throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY,
135-
"Attempted to unwrap single value array for single '" + _resolver.getEnumClass().getName() + "' value but there was more than a single value in the array");
146+
"Attempted to unwrap single value array for single '" + _enumClass().getName() + "' value but there was more than a single value in the array");
136147
}
137148
return parsed;
138149
}
139-
throw ctxt.mappingException(_resolver.getEnumClass());
150+
throw ctxt.mappingException(_enumClass());
140151
}
141152

142153
protected void _checkFailOnNumber(DeserializationContext ctxt) throws IOException
@@ -146,6 +157,10 @@ protected void _checkFailOnNumber(DeserializationContext ctxt) throws IOExceptio
146157
}
147158
}
148159

160+
protected Class<?> _enumClass() {
161+
return handledType();
162+
}
163+
149164
/*
150165
/**********************************************************
151166
/* Additional helper classes

src/main/java/com/fasterxml/jackson/databind/util/CompactStringObjectMap.java

Lines changed: 69 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,74 +17,57 @@
1717
public abstract class CompactStringObjectMap
1818
{
1919
public static CompactStringObjectMap empty() {
20-
return Empty.instance;
20+
return Small.EMPTY;
2121
}
2222

2323
public static <T> CompactStringObjectMap construct(Map<String,T> contents)
2424
{
2525
if (contents.size() == 0) { // can this occur?
26-
return Empty.instance;
26+
return empty();
2727
}
2828
Iterator<Map.Entry<String,T>> it = contents.entrySet().iterator();
2929
switch (contents.size()) {
3030
case 1:
31-
return new Small1(it.next());
31+
return new Small(it.next(), null);
3232
case 2:
33-
return new Small2(it.next(), it.next());
33+
return new Small(it.next(), it.next());
3434
}
3535
// General-purpose "big" one needed:
3636
return Big.construct(contents);
3737
}
3838

39-
public abstract Object findField(String key);
39+
public abstract Object find(String key);
4040

41-
static class Empty extends CompactStringObjectMap {
42-
public final static Empty instance = new Empty();
43-
44-
private Empty() {
45-
super();
46-
}
47-
48-
@Override
49-
public Object findField(String key) {
50-
return null;
51-
}
52-
}
53-
54-
static class Small1 extends CompactStringObjectMap
55-
{
56-
protected final String key1;
57-
protected final Object value1;
58-
59-
private Small1(Map.Entry<String,?> entry) {
60-
key1 = entry.getKey();
61-
value1 = entry.getValue();
62-
}
63-
64-
@Override
65-
public Object findField(String key) {
66-
if (key == key1 || key.equals(key1)) {
67-
return value1;
68-
}
69-
return null;
70-
}
71-
}
72-
73-
final static class Small2 extends CompactStringObjectMap
41+
public abstract List<String> keys();
42+
43+
final static class Small extends CompactStringObjectMap
7444
{
45+
public final static Small EMPTY = new Small(null, null);
46+
7547
protected final String key1, key2;
7648
protected final Object value1, value2;
7749

78-
private Small2(Map.Entry<String,?> e1, Map.Entry<String,?> e2)
50+
private Small(Map.Entry<String,?> e1, Map.Entry<String,?> e2)
7951
{
80-
key1 = e1.getKey();
81-
value1 = e1.getValue();
82-
key2 = e2.getKey();
83-
value2 = e2.getValue();
52+
if (e1 == null) {
53+
key1 = null;
54+
value1 = null;
55+
} else {
56+
key1 = e1.getKey();
57+
value1 = e1.getValue();
58+
}
59+
if (e2 == null) {
60+
key2 = null;
61+
value2 = null;
62+
} else {
63+
key2 = e2.getKey();
64+
value2 = e2.getValue();
65+
}
8466
}
8567

8668
@Override
87-
public Object findField(String key) {
69+
public Object find(String key) {
70+
// no assumption of key being intern()ed:
8871
if (key.equals(key1)) {
8972
return value1;
9073
}
@@ -93,7 +76,19 @@ public Object findField(String key) {
9376
}
9477
return null;
9578
}
96-
}
79+
80+
@Override
81+
public List<String> keys() {
82+
ArrayList<String> keys = new ArrayList<String>(2);
83+
if (key1 != null) {
84+
keys.add(key1);
85+
}
86+
if (key2 != null) {
87+
keys.add(key2);
88+
}
89+
return keys;
90+
}
91+
}
9792

9893
/**
9994
* Raw mapping from keys to indices, optimized for fast access via
@@ -151,8 +146,24 @@ public static <T> Big construct(Map<String,T> all)
151146
return new Big(mask, spills, keys, fieldHash);
152147
}
153148

149+
private final static int findSize(int size)
150+
{
151+
if (size <= 5) {
152+
return 8;
153+
}
154+
if (size <= 12) {
155+
return 16;
156+
}
157+
int needed = size + (size >> 2); // at most 80% full
158+
int result = 32;
159+
while (result < needed) {
160+
result += result;
161+
}
162+
return result;
163+
}
164+
154165
@Override
155-
public Object findField(String key) {
166+
public Object find(String key) {
156167
int slot = key.hashCode() & _hashMask;
157168
String match = _keys[slot];
158169
if ((match == key) || key.equals(match)) {
@@ -171,22 +182,6 @@ public Object findField(String key) {
171182
return _findFromSpill(key);
172183
}
173184

174-
private final static int findSize(int size)
175-
{
176-
if (size <= 5) {
177-
return 8;
178-
}
179-
if (size <= 12) {
180-
return 16;
181-
}
182-
int needed = size + (size >> 2); // at most 80% full
183-
int result = 32;
184-
while (result < needed) {
185-
result += result;
186-
}
187-
return result;
188-
}
189-
190185
private Object _findFromSpill(String key) {
191186
int hashSize = _hashMask+1;
192187
int i = hashSize + (hashSize>>1);
@@ -197,5 +192,16 @@ private Object _findFromSpill(String key) {
197192
}
198193
return null;
199194
}
200-
}
195+
196+
@Override
197+
public List<String> keys() {
198+
List<String> keys = new ArrayList<String>(_keys.length >> 1);
199+
for (String key : _keys) {
200+
if (key != null) {
201+
keys.add(key);
202+
}
203+
}
204+
return keys;
205+
}
206+
}
201207
}

src/main/java/com/fasterxml/jackson/databind/util/EnumResolver.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ public static EnumResolver constructUnsafeUsingMethod(Class<?> rawEnumCls, Metho
116116
Class<Enum<?>> enumCls = (Class<Enum<?>>) rawEnumCls;
117117
return constructUsingMethod(enumCls, accessor);
118118
}
119+
120+
public CompactStringObjectMap constructLookup() {
121+
return CompactStringObjectMap.construct(_enumsById);
122+
}
119123

120124
public Enum<?> findEnum(String key) { return _enumsById.get(key); }
121125

@@ -126,6 +130,10 @@ public Enum<?> getEnum(int index) {
126130
return _enums[index];
127131
}
128132

133+
public Enum<?>[] getRawEnums() {
134+
return _enums;
135+
}
136+
129137
public List<Enum<?>> getEnums() {
130138
ArrayList<Enum<?>> enums = new ArrayList<Enum<?>>(_enums.length);
131139
for (Enum<?> e : _enums) {

0 commit comments

Comments
 (0)