Skip to content

Commit b0a5f91

Browse files
authored
Merge pull request #83 from MikeDombo/jsonproperty-enum
feature: support JsonProperty annotation on enum values
2 parents 24c36c4 + 7805a68 commit b0a5f91

File tree

6 files changed

+133
-26
lines changed

6 files changed

+133
-26
lines changed

jr-annotation-support/src/main/java/com/fasterxml/jackson/jr/annotationsupport/AnnotationBasedIntrospector.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ protected void _findMethods() {
276276

277277
protected void _findMethods(final Class<?> currType)
278278
{
279-
if (currType == null || currType == Object.class) {
279+
if (currType == null || currType == Object.class || currType == Enum.class) {
280280
return;
281281
}
282282
// Start with base type methods (so overrides work)
@@ -415,7 +415,7 @@ protected void _checkSetterMethod(Method m)
415415
protected boolean _isFieldVisible(Field f) {
416416
// Consider transient and static-final to be non-visible
417417
// TODO: (maybe?) final
418-
return !(Modifier.isFinal(f.getModifiers()) && Modifier.isStatic(f.getModifiers()))
418+
return !(Modifier.isFinal(f.getModifiers()) && Modifier.isStatic(f.getModifiers()) && !f.isEnumConstant())
419419
&& !Modifier.isTransient(f.getModifiers())
420420
&& _visibility.getFieldVisibility().isVisible(f);
421421
}
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
package com.fasterxml.jackson.jr.annotationsupport;
22

3+
import java.io.IOException;
4+
import java.lang.reflect.Field;
5+
import java.util.*;
6+
37
import com.fasterxml.jackson.annotation.JsonAutoDetect;
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
import com.fasterxml.jackson.core.JsonGenerator;
410
import com.fasterxml.jackson.jr.ob.api.ReaderWriterModifier;
11+
import com.fasterxml.jackson.jr.ob.api.ValueWriter;
512
import com.fasterxml.jackson.jr.ob.impl.JSONReader;
613
import com.fasterxml.jackson.jr.ob.impl.JSONWriter;
714
import com.fasterxml.jackson.jr.ob.impl.POJODefinition;
815

9-
public class AnnotationBasedValueRWModifier
10-
extends ReaderWriterModifier
11-
{
16+
public class AnnotationBasedValueRWModifier extends ReaderWriterModifier {
17+
// Matches SER_ENUM code in ValueLocatorBase
18+
protected static final int SER_ENUM = 23;
19+
1220
/**
1321
* Visibility settings to use for auto-detecting accessors.
1422
*/
@@ -19,17 +27,48 @@ public AnnotationBasedValueRWModifier(JsonAutoDetect.Value visibility) {
1927
}
2028

2129
@Override
22-
public POJODefinition pojoDefinitionForDeserialization(JSONReader readContext,
23-
Class<?> pojoType)
24-
{
25-
return AnnotationBasedIntrospector.pojoDefinitionForDeserialization(readContext,
26-
pojoType, _visibility);
30+
public POJODefinition pojoDefinitionForDeserialization(JSONReader readContext, Class<?> pojoType) {
31+
return AnnotationBasedIntrospector.pojoDefinitionForDeserialization(readContext, pojoType, _visibility);
32+
}
33+
34+
@Override
35+
public POJODefinition pojoDefinitionForSerialization(JSONWriter writeContext, Class<?> pojoType) {
36+
return AnnotationBasedIntrospector.pojoDefinitionForSerialization(writeContext, pojoType, _visibility);
2737
}
2838

2939
@Override
30-
public POJODefinition pojoDefinitionForSerialization(JSONWriter writeContext,
31-
Class<?> pojoType) {
32-
return AnnotationBasedIntrospector.pojoDefinitionForSerialization(writeContext,
33-
pojoType, _visibility);
40+
public ValueWriter overrideStandardValueWriter(JSONWriter writeContext, Class<?> type, int stdTypeId) {
41+
if (stdTypeId == SER_ENUM) {
42+
return new EnumWriter(type);
43+
}
44+
return null;
45+
}
46+
47+
private static class EnumWriter implements ValueWriter {
48+
private final Class<?> _valueType;
49+
private final Map<String, String> enumMap;
50+
51+
public EnumWriter(Class<?> type) {
52+
_valueType = type;
53+
enumMap = new HashMap<String, String>();
54+
Field[] fields = type.getDeclaredFields();
55+
for (Field field : fields) {
56+
if (field.isAnnotationPresent(JsonProperty.class)) {
57+
enumMap.put(field.getName(), field.getAnnotation(JsonProperty.class).value());
58+
} else {
59+
enumMap.put(field.getName(), field.getName());
60+
}
61+
}
62+
}
63+
64+
@Override
65+
public void writeValue(JSONWriter context, JsonGenerator g, Object value) throws IOException {
66+
context.writeValue(enumMap.get(((Enum) value).name()));
67+
}
68+
69+
@Override
70+
public Class<?> valueType() {
71+
return _valueType;
72+
}
3473
}
3574
}

jr-annotation-support/src/test/java/com/fasterxml/jackson/jr/annotationsupport/ASTestBase.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Arrays;
44

5+
import com.fasterxml.jackson.annotation.JsonProperty;
56
import com.fasterxml.jackson.jr.ob.JSON;
67

78
import junit.framework.TestCase;
@@ -10,6 +11,8 @@ public abstract class ASTestBase extends TestCase
1011
{
1112
protected enum ABC { A, B, C; }
1213

14+
protected enum ABCRename { @JsonProperty("A1") A, @JsonProperty("B1") B, C; }
15+
1316
protected static class NameBean {
1417
protected String first, last;
1518

@@ -25,7 +28,7 @@ public NameBean(String f, String l) {
2528
public void setFirst(String n) { first = n; }
2629
public void setLast(String n) { last = n; }
2730
}
28-
31+
2932
protected void verifyException(Throwable e, String... matches)
3033
{
3134
String msg = e.getMessage();

jr-annotation-support/src/test/java/com/fasterxml/jackson/jr/annotationsupport/BasicRenameTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,40 @@ public void testBasicRenameOnDeserialize() throws Exception
6060
assertEquals("Bob", result._first);
6161
assertEquals("Burger", result._last);
6262
}
63+
64+
public void testEnumRenameOnSerialize() throws Exception
65+
{
66+
ABCRename inputA = ABCRename.A;
67+
// default
68+
assertEquals(a2q("\"A\""), JSON.std.asString(inputA));
69+
// with annotations
70+
assertEquals(a2q("\"A1\""), JSON_WITH_ANNO.asString(inputA));
71+
72+
ABCRename inputB = ABCRename.B;
73+
// default
74+
assertEquals(a2q("\"B\""), JSON.std.asString(inputB));
75+
// with annotations
76+
assertEquals(a2q("\"B1\""), JSON_WITH_ANNO.asString(inputB));
77+
78+
ABCRename inputC = ABCRename.C;
79+
// default
80+
assertEquals(a2q("\"C\""), JSON.std.asString(inputC));
81+
// with annotations
82+
assertEquals(a2q("\"C\""), JSON_WITH_ANNO.asString(inputC));
83+
}
84+
85+
public void testEnumRenameOnDeserialize() throws Exception
86+
{
87+
String jsonA = a2q("\"A1\"");
88+
ABCRename resultA = JSON_WITH_ANNO.beanFrom(ABCRename.class, jsonA);
89+
assertEquals(ABCRename.A, resultA);
90+
91+
String jsonB = a2q("\"B1\"");
92+
ABCRename resultB = JSON_WITH_ANNO.beanFrom(ABCRename.class, jsonB);
93+
assertEquals(ABCRename.B, resultB);
94+
95+
String jsonC = a2q("\"C\"");
96+
ABCRename resultC = JSON_WITH_ANNO.beanFrom(ABCRename.class, jsonC);
97+
assertEquals(ABCRename.C, resultC);
98+
}
6399
}

jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueReaderLocator.java

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public class ValueReaderLocator
6464
/* Caching
6565
/**********************************************************************
6666
*/
67-
67+
6868
/**
6969
* Set of {@link ValueReader}s that we have resolved
7070
*/
@@ -100,7 +100,7 @@ public class ValueReaderLocator
100100
/* Instance state, caching
101101
/**********************************************************************
102102
*/
103-
103+
104104
/**
105105
* Reusable lookup key; only used by per-thread instances.
106106
*/
@@ -143,14 +143,14 @@ protected ValueReaderLocator(ValueReaderLocator base,
143143
// create new cache as there may be custom writers:
144144
_knownReaders = new ConcurrentHashMap<ClassKey, ValueReader>(10, 0.75f, 2);
145145
_readerLock = new Object();
146-
146+
147147
_features = base._features;
148148
_readContext = base._readContext;
149149
_readerProvider = rwp;
150150
_readerModifier = rwm;
151151
_typeResolver = base._typeResolver;
152152
}
153-
153+
154154
public final static ValueReaderLocator blueprint(ReaderWriterProvider rwp, ReaderWriterModifier rwm) {
155155
return new ValueReaderLocator(rwp, rwm);
156156
}
@@ -168,7 +168,7 @@ public ValueReaderLocator with(ReaderWriterModifier rwm) {
168168
}
169169
return new ValueReaderLocator(this, _readerProvider, rwm);
170170
}
171-
171+
172172
public ValueReaderLocator perOperationInstance(JSONReader r, int features) {
173173
return new ValueReaderLocator(this, features & CACHE_FLAGS, r);
174174
}
@@ -188,7 +188,7 @@ public ValueReaderLocator perOperationInstance(JSONReader r, int features) {
188188
/* Public API, operations
189189
/**********************************************************************
190190
*/
191-
191+
192192
/**
193193
* Method used during deserialization to find handler for given
194194
* non-generic type: will first check for already resolved (and cached) readers
@@ -295,10 +295,29 @@ protected ValueReader arrayReader(Class<?> contextType, Class<?> arrayType) {
295295
}
296296

297297
protected ValueReader enumReader(Class<?> enumType) {
298+
// Call pojoDefinitionForDeserialization so that the annotation support extension can get custom names for
299+
// enum values
300+
POJODefinition def = null;
301+
if (_readerModifier != null) {
302+
def = _readerModifier.pojoDefinitionForDeserialization(_readContext, enumType);
303+
}
304+
Map<String, Object> byName = new HashMap<String, Object>();
298305
Object[] enums = enumType.getEnumConstants();
299-
Map<String,Object> byName = new HashMap<String,Object>();
300-
for (Object e : enums) {
301-
byName.put(e.toString(), e);
306+
if (def == null) {
307+
for (Object e : enums) {
308+
byName.put(e.toString(), e);
309+
}
310+
} else {
311+
for (POJODefinition.Prop e : def.getProperties()) {
312+
if (e.field != null && e.field.isEnumConstant()) {
313+
try {
314+
byName.put(e.name, e.field.get(null));
315+
} catch (IllegalAccessException ex) {
316+
// Don't believe that this should be possible, but raise it up just in case
317+
throw new RuntimeException(ex);
318+
}
319+
}
320+
}
302321
}
303322
return new EnumReader(enumType, enums, byName);
304323
}

jr-objects/src/main/java/com/fasterxml/jackson/jr/ob/impl/ValueWriterLocator.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ private int _modifyAndRegisterWriter(Class<?> rawType, ValueWriter w) {
251251
}
252252
return _registerWriter(rawType, w);
253253
}
254-
254+
255255
private int _registerWriter(Class<?> rawType, ValueWriter valueWriter) {
256256
// Due to concurrent access, possible that someone might have added it
257257
synchronized (_knownWriters) {
@@ -269,7 +269,7 @@ private int _registerWriter(Class<?> rawType, ValueWriter valueWriter) {
269269
return typeId;
270270
}
271271
}
272-
272+
273273
protected BeanPropertyWriter[] _resolveBeanForSer(Class<?> raw, POJODefinition beanDef)
274274
{
275275
final List<POJODefinition.Prop> rawProps = beanDef.getProperties();
@@ -310,6 +310,16 @@ protected BeanPropertyWriter[] _resolveBeanForSer(Class<?> raw, POJODefinition b
310310
}
311311
}
312312
int typeId = _findSimpleType(type, true);
313+
// Give plugin the opportunity to override standard value writer
314+
if (_writerModifier != null && typeId != 0) {
315+
Integer I = _knownSerTypes.get(new ClassKey(type, _features));
316+
if (I == null) {
317+
ValueWriter w = _writerModifier.overrideStandardValueWriter(_writeContext, type, typeId);
318+
if (w != null) {
319+
typeId = _registerWriter(type, w);
320+
}
321+
}
322+
}
313323
props.add(new BeanPropertyWriter(typeId, rawProp.name, rawProp.field, m));
314324
}
315325
int plen = props.size();

0 commit comments

Comments
 (0)