All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasterxml.jackson.databind.ser.std.EnumSerializer Maven / Gradle / Ivy

The newest version!
package com.fasterxml.jackson.databind.ser.std;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;

import com.fasterxml.jackson.core.*;

import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
import com.fasterxml.jackson.databind.introspect.EnumNamingStrategyFactory;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonStringFormatVisitor;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.util.EnumValues;

/**
 * Standard serializer used for {@link java.lang.Enum} types.
 *

* Based on {@link StdScalarSerializer} since the JSON value is * scalar (String). */ @JacksonStdImpl public class EnumSerializer extends StdScalarSerializer> implements ContextualSerializer { private static final long serialVersionUID = 1L; /** * This map contains pre-resolved values (since there are ways * to customize actual String constants to use) to use as * serializations. */ protected final EnumValues _values; /** * Flag that is set if we statically know serialization choice * between index and textual format (null if it needs to be dynamically * checked). * * @since 2.1 */ protected final Boolean _serializeAsIndex; /** * Map with key as converted property class defined implementation of {@link EnumNamingStrategy} * and with value as Enum names collected using Enum.name(). * * @since 2.15 */ protected final EnumValues _valuesByEnumNaming; /** * Map that contains pre-resolved values for {@link Enum#toString} to use for serialization, * while respecting {@link com.fasterxml.jackson.annotation.JsonProperty} * and {@link com.fasterxml.jackson.databind.cfg.EnumFeature#WRITE_ENUMS_TO_LOWERCASE}. * * @since 2.16 */ protected final EnumValues _valuesByToString; /* /********************************************************** /* Construction, initialization /********************************************************** */ /** * @deprecated Since 2.16 */ @Deprecated // since 2.16 public EnumSerializer(EnumValues v, Boolean serializeAsIndex) { this(v, serializeAsIndex, null, null); } /** * @since 2.15 * @deprecated Since 2.16 */ @Deprecated public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesByEnumNaming) { this(v, serializeAsIndex, valuesByEnumNaming, null); } /** * @since 2.16 */ public EnumSerializer(EnumValues v, Boolean serializeAsIndex, EnumValues valuesByEnumNaming, EnumValues valuesByToString) { super(v.getEnumClass(), false); _values = v; _serializeAsIndex = serializeAsIndex; _valuesByEnumNaming = valuesByEnumNaming; _valuesByToString = valuesByToString; } /** * Factory method used by {@link com.fasterxml.jackson.databind.ser.BasicSerializerFactory} * for constructing serializer instance of Enum types. * * @since 2.1 */ @SuppressWarnings("unchecked") public static EnumSerializer construct(Class enumClass, SerializationConfig config, BeanDescription beanDesc, JsonFormat.Value format) { /* 08-Apr-2015, tatu: As per [databind#749], we cannot statically determine * between name() and toString(), need to construct `EnumValues` with names, * handle toString() case dynamically (for example) */ EnumValues v = EnumValues.constructFromName(config, beanDesc.getClassInfo()); EnumValues valuesByEnumNaming = constructEnumNamingStrategyValues(config, (Class>) enumClass, beanDesc.getClassInfo()); EnumValues valuesByToString = EnumValues.constructFromToString(config, beanDesc.getClassInfo()); Boolean serializeAsIndex = _isShapeWrittenUsingIndex(enumClass, format, true, null); return new EnumSerializer(v, serializeAsIndex, valuesByEnumNaming, valuesByToString); } /** * To support some level of per-property configuration, we will need * to make things contextual. We are limited to "textual vs index" * choice here, however. */ @Override public JsonSerializer createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException { JsonFormat.Value format = findFormatOverrides(serializers, property, handledType()); if (format != null) { Class type = handledType(); Boolean serializeAsIndex = _isShapeWrittenUsingIndex(type, format, false, _serializeAsIndex); if (!Objects.equals(serializeAsIndex, _serializeAsIndex)) { return new EnumSerializer(_values, serializeAsIndex, _valuesByEnumNaming, _valuesByToString); } } return this; } /* /********************************************************** /* Extended API for Jackson databind core /********************************************************** */ public EnumValues getEnumValues() { return _values; } /* /********************************************************** /* Actual serialization /********************************************************** */ @Override public final void serialize(Enum en, JsonGenerator gen, SerializerProvider serializers) throws IOException { if (_valuesByEnumNaming != null) { gen.writeString(_valuesByEnumNaming.serializedValueFor(en)); return; } if (_serializeAsIndex(serializers)) { gen.writeNumber(en.ordinal()); return; } // [databind#749]: or via toString()? if (serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { gen.writeString(_valuesByToString.serializedValueFor(en)); return; } gen.writeString(_values.serializedValueFor(en)); } /* /********************************************************** /* Schema support /********************************************************** */ /** * @deprecated Since 2.15 */ @Deprecated @Override public JsonNode getSchema(SerializerProvider provider, Type typeHint) { if (_serializeAsIndex(provider)) { return createSchemaNode("integer", true); } ObjectNode objectNode = createSchemaNode("string", true); if (typeHint != null) { JavaType type = provider.constructType(typeHint); if (type.isEnumType()) { ArrayNode enumNode = objectNode.putArray("enum"); for (SerializableString value : _values.values()) { enumNode.add(value.getValue()); } } } return objectNode; } @Override public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint) throws JsonMappingException { SerializerProvider serializers = visitor.getProvider(); if (_serializeAsIndex(serializers)) { visitIntFormat(visitor, typeHint, JsonParser.NumberType.INT); return; } JsonStringFormatVisitor stringVisitor = visitor.expectStringFormat(typeHint); if (stringVisitor != null) { Set enums = new LinkedHashSet(); // Use toString()? if ((serializers != null) && serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_TO_STRING)) { for (SerializableString value : _valuesByToString.values()) { enums.add(value.getValue()); } } else { // No, serialize using name() or explicit overrides for (SerializableString value : _values.values()) { enums.add(value.getValue()); } } stringVisitor.enumTypes(enums); } } /* /********************************************************** /* Helper methods /********************************************************** */ protected final boolean _serializeAsIndex(SerializerProvider serializers) { if (_serializeAsIndex != null) { return _serializeAsIndex; } return serializers.isEnabled(SerializationFeature.WRITE_ENUMS_USING_INDEX); } /** * Helper method called to check whether serialization should be done using * index (number) or not. */ protected static Boolean _isShapeWrittenUsingIndex(Class enumClass, JsonFormat.Value format, boolean fromClass, Boolean defaultValue) { JsonFormat.Shape shape = (format == null) ? null : format.getShape(); if (shape == null) { return defaultValue; } // i.e. "default", check dynamically if (shape == Shape.ANY || shape == Shape.SCALAR) { return defaultValue; } // 19-May-2016, tatu: also consider "natural" shape if (shape == Shape.STRING || shape == Shape.NATURAL) { return Boolean.FALSE; } // 01-Oct-2014, tatu: For convenience, consider "as-array" to also mean 'yes, use index') if (shape.isNumeric() || (shape == Shape.ARRAY)) { return Boolean.TRUE; } // 07-Mar-2017, tatu: Also means `OBJECT` not available as property annotation... throw new IllegalArgumentException(String.format( "Unsupported serialization shape (%s) for Enum %s, not supported as %s annotation", shape, enumClass.getName(), (fromClass? "class" : "property"))); } /** * Factory method used to resolve an instance of {@link EnumValues} * with {@link EnumNamingStrategy} applied for the target class. * * @since 2.15 */ protected static EnumValues constructEnumNamingStrategyValues(SerializationConfig config, Class> enumClass, AnnotatedClass annotatedClass) { Object namingDef = config.getAnnotationIntrospector().findEnumNamingStrategy(config, annotatedClass); EnumNamingStrategy enumNamingStrategy = EnumNamingStrategyFactory.createEnumNamingStrategyInstance( namingDef, config.canOverrideAccessModifiers()); return enumNamingStrategy == null ? null : EnumValues.constructUsingEnumNamingStrategy( config, annotatedClass, enumNamingStrategy); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy