簡體   English   中英

使用Jackson反序列化為String或Object

[英]Deserialize to String or Object using Jackson

我有一個有時看起來像這樣的對象:

{
   "foo" : "bar",
   "fuzz" : "bla"
}

有時看起來像這樣:

{
   "foo" : { "value" : "bar", "baz": "asdf" },
   "fuzz" : { "thing" : "bla", "blip" : "asdf" }
}

這些類看起來像:

public class Foo {
   String value;
   String baz;
}

public class Fuzz {
   String thing;
   String blip;
}

第一種情況是第二種情況的簡寫。 我想總是反序列化到第二種情況。

進一步 - 這是我們代碼中非常常見的模式,所以我希望能夠以通用方式進行序列化,因為上面有類似於Foo其他類具有使用String作為語法糖的相同模式一個更復雜的對象。

我想像使用它的代碼看起來像這樣


public class Thing { 
  @JsonProperty("fuzz")
  Fuzz fuzz;

  @JsonProperty("foo")
  Foo foo;
}

如何編寫通常處理這兩種情況的自定義反序列化器(或其他模塊)?

為了使它通用,我們需要能夠指定我們想要在JSON primitive對象中設置的名稱。 一些靈活性給出了注釋方法。 讓我們定義簡單的注釋:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface JsonPrimitiveName {
    String value();
}

名稱表示:如果原語將出現在JSON使用value()來獲取給定基元的屬性名稱。 它將JSON primitivePOJO字段綁定。 處理JSON objectJSON primitive簡單反序列化器:

class PrimitiveOrPojoJsonDeserializer extends JsonDeserializer implements ContextualDeserializer {

    private String primitiveName;
    private JavaType type;

    @Override
    public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(type);
        if (p.currentToken() == JsonToken.START_OBJECT) {
            return deserializer.deserialize(p, ctxt);
        } else if (p.currentToken() == JsonToken.VALUE_STRING) {
            BeanDeserializer beanDeserializer = (BeanDeserializer) deserializer;
            try {
                Object instance = beanDeserializer.getValueInstantiator().getDefaultCreator().call();
                SettableBeanProperty property = beanDeserializer.findProperty(primitiveName);
                property.deserializeAndSet(p, ctxt, instance);
                return instance;
            } catch (Exception e) {
                throw JsonMappingException.from(p, e.getMessage());
            }
        }

        return null;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        JsonPrimitiveName annotation = property.getAnnotation(JsonPrimitiveName.class);

        PrimitiveOrPojoJsonDeserializer deserializer = new PrimitiveOrPojoJsonDeserializer();
        deserializer.primitiveName = annotation.value();
        deserializer.type = property.getType();

        return deserializer;
    }
}

現在我們需要注釋POJO字段,如下所示:

class Root {

    @JsonPrimitiveName("value")
    @JsonDeserialize(using = PrimitiveOrPojoJsonDeserializer.class)
    private Foo foo;

    @JsonPrimitiveName("thing")
    @JsonDeserialize(using = PrimitiveOrPojoJsonDeserializer.class)
    private Fuzz fuzz;

    // getters, setters
}

我假設所有類都是POJO並遵循所有規則 - 有getterssetters和默認構造函數。 如果構造函數不存在,您需要以某種方式更改此beanDeserializer.getValueInstantiator().getDefaultCreator().call()行以滿足您的要求。

應用示例:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.readValue(jsonFile, Root.class));
    }
}

打印縮短的JSON

Root{foo=Foo{value='bar', baz='null'}, fuzz=Fuzz{thing='bla', blip='null'}}

並且對於完整的JSON有效負載:

Root{foo=Foo{value='bar', baz='asdf'}, fuzz=Fuzz{thing='bla', blip='asdf'}}

暫無
暫無

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

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