簡體   English   中英

您如何修改未注釋枚舉的默認枚舉(反)序列化,但在 Jackson 中保留標准行為(@JsonProperty/@JsonValue/...)?

[英]How do you modify default enum (de)serialization for non-annotated enums but retain standard behavior (@JsonProperty/@JsonValue/...) in Jackson?

目前 jackson (uncustomized) 像這樣序列化枚舉:

  1. 如果有@JsonProperty@JsonValue ,它們用於派生序列化名稱
  2. 否則,執行標准序列化:可能使用 index 或toString() (取決於映射器設置),或默認調用.name()

對於反序列化,是這樣的:

  1. 如果有@JsonProperty@JsonValue@JsonCreator ,它們會影響反序列化
  2. 否則,使用標准反序列化來反映序列化。

我想在這兩種情況下都保留第 1 項(即仍然支持所有 3 個注釋,如果我遺漏了一些注釋,或者更多),但修改“默認情況”的行為:例如,始終將枚舉序列化為.name().toLowercase()如果沒有注釋。

我可以使用addSerializer()addDeserializer()或 (de)serializer 修改機制,但這些都不允許簡單而優雅的解決方案。 我所能發明的只是從 jackson 復制/粘貼大量代碼(這是丑陋和脆弱的),或者,使用修改機制,內省模擬 jackson 涉及的邏輯的枚舉類,以識別“默認”邏輯何時適用的情況,然后使用我的“小寫”策略。

有沒有更好的方法來修改“默認”序列化策略,同時仍然保留所有“非默認”情況?

您可以插入一個新的AnnotationIntrospector,findEnumValues方法會更改枚舉名稱。 EnumRenamingModuletherapi-JSON-RPC項目使用了這種技術。 (免責聲明:這是我的寵物項目。)這是從 GitHub 存儲庫復制的代碼:

package com.github.therapi.jackson.enums;

import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;

/**
 * Customizes the way Jackson serializes enums.
 */
public abstract class EnumRenamingModule extends SimpleModule {
    private boolean overrideExistingNames;

    public EnumRenamingModule() {
        super("therapi-enum-renaming");
    }

    /**
     * Configures the module to clobber any enum names set by
     * a previous annotation introspector.
     */
    public EnumRenamingModule overrideExistingNames() {
        this.overrideExistingNames = true;
        return this;
    }

    @Override
    public void setupModule(Module.SetupContext context) {
        super.setupModule(context);
        context.insertAnnotationIntrospector(new EnumNamingAnnotationIntrospector());
    }

    private class EnumNamingAnnotationIntrospector extends NopAnnotationIntrospector {
        public String[] findEnumValues(Class<?> enumType, Enum<?>[] enumValues, String[] names) {
            for (int i = 0; i < enumValues.length; i++) {
                if (names[i] == null || overrideExistingNames) {
                    names[i] = EnumRenamingModule.this.getName(enumValues[i]);
                }
            }
            return names;
        }
    }

    /**
     * @param value the enum value to inspect
     * @return the JSON name for the enum value, or {@code null} to delegate to the next introspector
     */
    protected abstract String getName(Enum<?> value);
}

創建一個子類來做你想要的轉換:

public class LowerCaseEnumModule extends EnumRenamingModule {
    @Override protected String getName(Enum<?> value) {
        return value.name().toLowerCase(Locale.ROOT);
    }
}

並使用您的 ObjectMapper 注冊它:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new LowerCaseEnumModule());

注解@JsonCreator用於反序列化(它是一個靜態工廠)。
注解@JsonValue用於序列化。
給定的例子對我有用:

class MyException extends RuntimeException {}
enum MyEnum {
    TEST;

    private final String value;

    private MyEnum() {
        this.value = this.name().toLowerCase();
    }

    @JsonValue
    public final String value() {
        return this.value;
    }

    @JsonCreator
    public static MyEnum forValue(String value) {
        return Arrays.stream(MyEnum.values()).filter(myEnum -> myEnum.value.equals(value)).findFirst().orElseThrow(MyException::new);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM