io.dropwizard.jackson.FuzzyEnumModule Maven / Gradle / Ivy
package io.dropwizard.jackson;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.Version;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.deser.Deserializers;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import io.dropwizard.util.Enums;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* A module for deserializing enums that is more permissive than the default.
*
* This deserializer is more permissive in the following ways:
*
* - Whitespace is permitted but stripped from the input.
* - Dashes and periods in the value are converted to underscores.
* - Matching against the enum values is case insensitive.
*
*/
public class FuzzyEnumModule extends Module {
private static class PermissiveEnumDeserializer extends StdScalarDeserializer> {
private static final long serialVersionUID = 1L;
private final Enum>[] constants;
private final List acceptedValues;
@SuppressWarnings("unchecked")
protected PermissiveEnumDeserializer(Class> clazz) {
super(clazz);
this.constants = ((Class>) handledType()).getEnumConstants();
this.acceptedValues = new ArrayList<>();
for (Enum> constant : constants) {
acceptedValues.add(constant.name());
}
}
@Override
public Enum> deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
Enum> constant = Enums.fromStringFuzzy(jp.getText(), constants);
if (constant != null) {
return constant;
}
throw ctxt.mappingException(jp.getText() + " was not one of " + acceptedValues);
}
}
private static class PermissiveEnumDeserializers extends Deserializers.Base {
@Override
@SuppressWarnings("unchecked")
public JsonDeserializer> findEnumDeserializer(Class> type,
DeserializationConfig config,
BeanDescription desc) throws JsonMappingException {
// If the user configured to use `toString` method to deserialize enums
if (config.hasDeserializationFeatures(
DeserializationFeature.READ_ENUMS_USING_TO_STRING.getMask())) {
return null;
}
// If there is a JsonCreator annotation we should use that instead of the PermissiveEnumDeserializer
final Collection factoryMethods = desc.getFactoryMethods();
if (factoryMethods != null) {
for (AnnotatedMethod am : factoryMethods) {
if (am.hasAnnotation(JsonCreator.class)) {
return null;
}
}
}
// If any enum choice is annotated with an annotation from jackson, defer to
// Jackson to do the deserialization
for (Field field : type.getFields()) {
for (Annotation annotation : field.getAnnotations()) {
final String packageName = annotation.annotationType().getPackage().getName();
if (packageName.equals("com.fasterxml.jackson.annotation")) {
return null;
}
}
}
return new PermissiveEnumDeserializer((Class>) type);
}
}
@Override
public String getModuleName() {
return "permissive-enums";
}
@Override
public Version version() {
return Version.unknownVersion();
}
@Override
public void setupModule(final SetupContext context) {
context.addDeserializers(new PermissiveEnumDeserializers());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy