1 package com.fasterxml.jackson.databind.ser.std;
2
3 import java.io.IOException;
4 import java.lang.reflect.Type;
5 import java.util.*;
6
7 import com.fasterxml.jackson.annotation.JsonFormat;
8 import com.fasterxml.jackson.annotation.JsonFormat.Shape;
9
10 import com.fasterxml.jackson.core.*;
11
12 import com.fasterxml.jackson.databind.*;
13 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
14 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
15 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
16 import com.fasterxml.jackson.databind.node.ArrayNode;
17 import com.fasterxml.jackson.databind.node.ObjectNode;
18 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
19 import com.fasterxml.jackson.databind.util.EnumValues;
20
21
27 @JacksonStdImpl
28 public class EnumSerializer
29 extends StdScalarSerializer<Enum<?>>
30 implements ContextualSerializer
31 {
32 private static final long serialVersionUID = 1L;
33
34
39 protected final EnumValues _values;
40
41
48 protected final Boolean _serializeAsIndex;
49
50
55
56 public EnumSerializer(EnumValues v, Boolean serializeAsIndex)
57 {
58 super(v.getEnumClass(), false);
59 _values = v;
60 _serializeAsIndex = serializeAsIndex;
61 }
62
63
69 @SuppressWarnings("unchecked")
70 public static EnumSerializer construct(Class<?> enumClass, SerializationConfig config,
71 BeanDescription beanDesc, JsonFormat.Value format)
72 {
73
77 EnumValues v = EnumValues.constructFromName(config, (Class<Enum<?>>) enumClass);
78 Boolean serializeAsIndex = _isShapeWrittenUsingIndex(enumClass, format, true, null);
79 return new EnumSerializer(v, serializeAsIndex);
80 }
81
82
87 @Override
88 public JsonSerializer<?> createContextual(SerializerProvider serializers,
89 BeanProperty property) throws JsonMappingException
90 {
91 JsonFormat.Value format = findFormatOverrides(serializers,
92 property, handledType());
93 if (format != null) {
94 Class<?> type = handledType();
95 Boolean serializeAsIndex = _isShapeWrittenUsingIndex(type,
96 format, false, _serializeAsIndex);
97 if (serializeAsIndex != _serializeAsIndex) {
98 return new EnumSerializer(_values, serializeAsIndex);
99 }
100 }
101 return this;
102 }
103
104
109
110 public EnumValues getEnumValues() { return _values; }
111
112
117
118 @Override
119 public final void serialize(Enum<?> en, JsonGenerator gen, SerializerProvider serializers)
120 throws IOException
121 {
122 if (_serializeAsIndex(serializers)) {
123 gen.writeNumber(en.ordinal());
124 return;
125 }
126
127 if (serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
128 gen.writeString(en.toString());
129 return;
130 }
131 gen.writeString(_values.serializedValueFor(en));
132 }
133
134
139
140 @Override
141 public JsonNode getSchema(SerializerProvider provider, Type typeHint)
142 {
143 if (_serializeAsIndex(provider)) {
144 return createSchemaNode("integer", true);
145 }
146 ObjectNode objectNode = createSchemaNode("string", true);
147 if (typeHint != null) {
148 JavaType type = provider.constructType(typeHint);
149 if (type.isEnumType()) {
150 ArrayNode enumNode = objectNode.putArray("enum");
151 for (SerializableString value : _values.values()) {
152 enumNode.add(value.getValue());
153 }
154 }
155 }
156 return objectNode;
157 }
158
159 @Override
160 public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
161 throws JsonMappingException
162 {
163 SerializerProvider serializers = visitor.getProvider();
164 if (_serializeAsIndex(serializers)) {
165 visitIntFormat(visitor, typeHint, JsonParser.NumberType.INT);
166 return;
167 }
168 JsonStringFormatVisitor stringVisitor = visitor.expectStringFormat(typeHint);
169 if (stringVisitor != null) {
170 Set<String> enums = new LinkedHashSet<String>();
171
172
173 if ((serializers != null) &&
174 serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) {
175 for (Enum<?> e : _values.enums()) {
176 enums.add(e.toString());
177 }
178 } else {
179
180 for (SerializableString value : _values.values()) {
181 enums.add(value.getValue());
182 }
183 }
184 stringVisitor.enumTypes(enums);
185 }
186 }
187
188
193
194 protected final boolean _serializeAsIndex(SerializerProvider serializers)
195 {
196 if (_serializeAsIndex != null) {
197 return _serializeAsIndex.booleanValue();
198 }
199 return serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX);
200 }
201
202
206 protected static Boolean _isShapeWrittenUsingIndex(Class<?> enumClass,
207 JsonFormat.Value format, boolean fromClass,
208 Boolean defaultValue)
209 {
210 JsonFormat.Shape shape = (format == null) ? null : format.getShape();
211 if (shape == null) {
212 return defaultValue;
213 }
214
215 if (shape == Shape.ANY || shape == Shape.SCALAR) {
216 return defaultValue;
217 }
218
219 if (shape == Shape.STRING || shape == Shape.NATURAL) {
220 return Boolean.FALSE;
221 }
222
223 if (shape.isNumeric() || (shape == Shape.ARRAY)) {
224 return Boolean.TRUE;
225 }
226
227 throw new IllegalArgumentException(String.format(
228 "Unsupported serialization shape (%s) for Enum %s, not supported as %s annotation",
229 shape, enumClass.getName(), (fromClass? "class" : "property")));
230 }
231 }
232