Jackson databind enum Groß-/Kleinschreibung nicht beachten

Lesezeit: 7 Minuten

Jackson databind enum Gros Kleinschreibung nicht beachten
tom91136

Wie kann ich eine JSON-Zeichenfolge deserialisieren, die Aufzählungswerte enthält, bei denen die Groß-/Kleinschreibung nicht beachtet wird? (mit Jackson Databind)

Der JSON-String:

[{"url": "foo", "type": "json"}]

und mein Java-POJO:

public static class Endpoint {

    public enum DataType {
        JSON, HTML
    }

    public String url;
    public DataType type;

    public Endpoint() {

    }

}

In diesem Fall Deserialisieren des JSON mit "type":"json" würde scheitern wo wie "type":"JSON" würde funktionieren. Aber ich möchte "json" aus Gründen der Namenskonvention auch zu funktionieren.

Das Serialisieren des POJO führt auch zu Großbuchstaben "type":"JSON"

Ich dachte an die Verwendung @JsonCreator und @JsonGetter:

    @JsonCreator
    private Endpoint(@JsonProperty("name") String url, @JsonProperty("type") String type) {
        this.url = url;
        this.type = DataType.valueOf(type.toUpperCase());
    }

    //....
    @JsonGetter
    private String getType() {
        return type.name().toLowerCase();
    }

Und es hat funktioniert. Aber ich habe mich gefragt, ob es eine bessere Lösung gibt, weil das für mich wie ein Hack aussieht.

Ich kann auch einen benutzerdefinierten Deserializer schreiben, aber ich habe viele verschiedene POJOs, die Aufzählungen verwenden, und es wäre schwer zu warten.

Kann jemand eine bessere Methode zum Serialisieren und Deserialisieren von Enumerationen mit der richtigen Namenskonvention vorschlagen?

Ich möchte nicht, dass meine Aufzählungen in Java Kleinbuchstaben sind!

Hier ist ein Testcode, den ich verwendet habe:

    String data = "[{"url":"foo", "type":"json"}]";
    Endpoint[] arr = new ObjectMapper().readValue(data, Endpoint[].class);
        System.out.println("POJO[]->" + Arrays.toString(arr));
        System.out.println("JSON ->" + new ObjectMapper().writeValueAsString(arr));

  • Welche Version von Jackson spielst du? Schauen Sie sich diesen JIRA an jira.codehaus.org/browse/JACKSON-861

    – Alexey Gavrilov

    11. Juni ’14 um 8:22

  • Ich verwende Jackson 2.2.3

    – tom91136

    11. Juni ’14 um 8:35

  • OK, ich habe gerade auf 2.4.0-RC3 aktualisiert

    – tom91136

    11. Juni ’14 um 8:56

Jackson databind enum Gros Kleinschreibung nicht beachten
davnicwil

Jackson 2.9

Dies ist jetzt ganz einfach, mit jackson-databind 2.9.0 und höher

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

// objectMapper now deserializes enums in a case-insensitive manner

Vollständiges Beispiel mit Tests

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {

  private enum TestEnum { ONE }
  private static class TestObject { public TestEnum testEnum; }

  public static void main (String[] args) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

    try {
      TestObject uppercase = 
        objectMapper.readValue("{ "testEnum": "ONE" }", TestObject.class);
      TestObject lowercase = 
        objectMapper.readValue("{ "testEnum": "one" }", TestObject.class);
      TestObject mixedcase = 
        objectMapper.readValue("{ "testEnum": "oNe" }", TestObject.class);

      if (uppercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize uppercase value");
      if (lowercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize lowercase value");
      if (mixedcase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize mixedcase value");

      System.out.println("Success: all deserializations worked");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

  • Dieser ist goldrichtig!

    – Vikas Prasad

    21. September ’17 um 7:14

  • Ich verwende 2.9.2 und es funktioniert nicht. Verursacht durch: com.fasterxml.jackson.databind.exc.InvalidFormatException: Wert vom Typ ….Gender` aus String “male” kann nicht deserialisiert werden: Wert ist keiner der deklarierten Enum-Instanznamen: [FAMALE, MALE]

    – Jordan Silva

    22. Okt ’17 um 17:19


  • @JordanSilva funktioniert sicherlich mit v2.9.2. Ich habe ein vollständiges Codebeispiel mit Tests zur Überprüfung hinzugefügt. Ich weiß nicht, was in Ihrem Fall passiert sein könnte, aber den Beispielcode mit ausführen jackson-databind 2.9.2 funktioniert insbesondere wie erwartet.

    – davnicwil

    6. Februar ’18 um 8:23


  • Mit Spring Boot können Sie die Eigenschaft einfach hinzufügen spring.jackson.mapper.accept-case-insensitive-enums=true

    – Arne Burmeister

    12. Juni ’19 um 8:06

  • @JordanSilva vielleicht versuchen Sie, Enum in Get-Parametern zu deserialisieren, wie ich es getan habe? =) Ich habe mein Problem gelöst und hier beantwortet. Hoffe es kann helfen

    – Konstantin Zyubin

    4. September ’19 um 17:22

1641663028 530 Jackson databind enum Gros Kleinschreibung nicht beachten
Sam Berry

Ich bin in meinem Projekt auf dasselbe Problem gestoßen, wir haben uns entschieden, unsere Enumerationen mit einem String-Schlüssel zu erstellen und zu verwenden @JsonValue und einen statischen Konstruktor für die Serialisierung bzw. Deserialisierung.

public enum DataType {
    JSON("json"), 
    HTML("html");

    private String key;

    DataType(String key) {
        this.key = key;
    }

    @JsonCreator
    public static DataType fromString(String key) {
        return key == null
                ? null
                : DataType.valueOf(key.toUpperCase());
    }

    @JsonValue
    public String getKey() {
        return key;
    }
}

  • Das sollte sein DataType.valueOf(key.toUpperCase()) – ansonsten hast du nicht wirklich etwas verändert. Defensiv codieren, um eine NPE zu vermeiden: return (null == key ? null : DataType.valueOf(key.toUpperCase()))

    – sarumont

    5. März ’15 um 20:13

  • Guter Fang @sarumont. Ich habe die Bearbeitung vorgenommen. Außerdem wurde die Methode in “fromString” in umbenannt spiel gut mit JAX-RS.

    – Sam Berry

    6. März ’15 um 1:29


  • Ich mochte diesen Ansatz, entschied mich aber für eine weniger ausführliche Variante, siehe unten.

    – Linqu

    26. April ’16 um 10:56

  • anscheinend die key Feld ist unnötig. In getKey, du könntest einfach return name().toLowerCase()

    – ja

    20. Juni ’16 um 10:39

  • Ich mag das Schlüsselfeld für den Fall, dass Sie die Aufzählung anders benennen möchten als das, was der Json haben wird. In meinem Fall sendet ein Legacy-System einen wirklich abgekürzten und schwer zu merkenden Namen für den gesendeten Wert, und ich kann dieses Feld verwenden, um in einen besseren Namen für meine Java-Enumeration zu übersetzen.

    – grinch

    8. Juni ’17 um 3:48

Seit Jackson 2.6 können Sie dies einfach tun:

    public enum DataType {
        @JsonProperty("json")
        JSON,
        @JsonProperty("html")
        HTML
    }

Ein vollständiges Beispiel finden Sie unter dieser Kern.

  • Beachten Sie, dass das Problem dadurch rückgängig gemacht wird. Jetzt akzeptiert Jackson nur Kleinbuchstaben und lehnt alle Werte in Großbuchstaben oder gemischten Großbuchstaben ab.

    – Pixelelefant

    26. Juli ’16 um 14:57

In Version 2.4.0 können Sie einen benutzerdefinierten Serializer für alle Enum-Typen registrieren (Verknüpfung zum Github-Problem). Sie können auch den standardmäßigen Enum-Deserializer selbst ersetzen, der den Enum-Typ erkennt. Hier ist ein Beispiel:

public class JacksonEnum {

    public static enum DataType {
        JSON, HTML
    }

    public static void main(String[] args) throws IOException {
        List<DataType> types = Arrays.asList(JSON, HTML);
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<Enum> modifyEnumDeserializer(DeserializationConfig config,
                                                              final JavaType type,
                                                              BeanDescription beanDesc,
                                                              final JsonDeserializer<?> deserializer) {
                return new JsonDeserializer<Enum>() {
                    @Override
                    public Enum deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
                        Class<? extends Enum> rawClass = (Class<Enum<?>>) type.getRawClass();
                        return Enum.valueOf(rawClass, jp.getValueAsString().toUpperCase());
                    }
                };
            }
        });
        module.addSerializer(Enum.class, new StdSerializer<Enum>(Enum.class) {
            @Override
            public void serialize(Enum value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
                jgen.writeString(value.name().toLowerCase());
            }
        });
        mapper.registerModule(module);
        String json = mapper.writeValueAsString(types);
        System.out.println(json);
        List<DataType> types2 = mapper.readValue(json, new TypeReference<List<DataType>>() {});
        System.out.println(types2);
    }
}

Ausgabe:

["json","html"]
[JSON, HTML]

1641663028 351 Jackson databind enum Gros Kleinschreibung nicht beachten
linqu

Ich habe mich für die Lösung von . entschieden Sam B. aber eine einfachere Variante.

public enum Type {
    PIZZA, APPLE, PEAR, SOUP;

    @JsonCreator
    public static Type fromString(String key) {
        for(Type type : Type.values()) {
            if(type.name().equalsIgnoreCase(key)) {
                return type;
            }
        }
        return null;
    }
}

  • Ich denke, das ist nicht einfacher. DataType.valueOf(key.toUpperCase()) ist eine direkte Instanziierung, bei der Sie eine Schleife haben. Dies könnte ein Problem für eine sehr zahlreiche Enumeration sein. Na sicher, valueOf kann eine IllegalArgumentException auslösen, die Ihr Code vermeidet. Dies ist also ein guter Vorteil, wenn Sie die Nullprüfung der Ausnahmeprüfung vorziehen.

    – Patrick M

    13. Dezember ’19 um 15:40

Wenn Sie Spring Boot verwenden 2.1.x mit Jackson 2.9 Sie können einfach diese Anwendungseigenschaft verwenden:

spring.jackson.mapper.accept-case-insensitive-enums=true

  • Ich denke, das ist nicht einfacher. DataType.valueOf(key.toUpperCase()) ist eine direkte Instanziierung, bei der Sie eine Schleife haben. Dies könnte ein Problem für eine sehr zahlreiche Enumeration sein. Na sicher, valueOf kann eine IllegalArgumentException auslösen, die Ihr Code vermeidet. Dies ist also ein guter Vorteil, wenn Sie die Nullprüfung der Ausnahmeprüfung vorziehen.

    – Patrick M

    13. Dezember ’19 um 15:40

Für diejenigen, die versuchen, Enum zu deserialisieren und dabei die Groß-/Kleinschreibung ignorieren GET-Parameter, das Aktivieren von ACCEPT_CASE_INSENSITIVE_ENUMS bringt nichts. Es wird nicht helfen, da diese Option nur für funktioniert Körperdeserialisierung. Versuchen Sie stattdessen Folgendes:

public class StringToEnumConverter implements Converter<String, Modes> {
    @Override
    public Modes convert(String from) {
        return Modes.valueOf(from.toUpperCase());
    }
}

und dann

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToEnumConverter());
    }
}

Die Antwort- und Codebeispiele stammen von Hier

.

185200cookie-checkJackson databind enum Groß-/Kleinschreibung nicht beachten

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy