簡體   English   中英

Jackson 鏈自定義解串器

[英]Jackson chain custom deserializers

如果您有一個類User

class User {
    private String firstName;
    private String lastName;
    private Address address; //object
}

和一個類Address分別:

class Address {
    private String streetName;
    private String postCode;
    private AddressType addressType; //enum
}

以及為兩者定制的 Jackson 反序列化器,是否有鏈接它們的好方法? 例如

class UserDeserialiser extends JsonDeserializer<User> {
    public User deserialize(JsonParser jp, DeserializationContext ctxt) {
        ObjectNode node = jp.getCodec().readTree(jp);

        User user = fetchUser();
        user.setFirstName(node.get("firstName").asText());
        user.setFirstName(node.get("lastName").asText());
        user.setAddress(???); // delegate to AddressDeserialiser here
    }
}

同樣在地址反序列化器中,是否可以委托默認的來處理枚舉(因為它可能具有自定義映射)?

class AddressDeserialiser extends JsonDeserializer<Address> {
    public User deserialize(JsonParser jp, DeserializationContext ctxt) {
        ObjectNode node = jp.getCodec().readTree(jp);

        Address user = fetchAddress();
        user.setStreetName(node.get("streetName").asText());
        user.setAddressType(???); // delegate to jackson default object mapper?
    }
}

不久前我也有同樣的需求,並想出了一個解決方案。 我不認為這是一個“不錯”的解決方案,因為它有點笨拙,但也許這會鼓勵某人寫出更好的答案。 那很好啊。


正如評論中提到的,這通常可以通過使用注釋來解決。 具體來說, @JacksonDeserialize注釋。

但是,如果(無論出於何種原因 - 並且有很多可能的原因)不希望使用注釋,則有必要為 JSON 樹的相關子樹顯式創建解析器。 這將選擇默認解串器已在對象映射器模塊中為相應類型注冊的自定義解串器。

參考您的示例的相關部分/模式,即包含??? 問號,這是:

JsonNode addressNode = node.get("address");
if (addressNode != null)
{
    JsonParser parser = addressNode.traverse();
    parser.setCodec(jp.getCodec());
    Address address = parser.readValueAs(Address.class);
    user.setAddress(address);
}

這是一個MCVE,顯示了這種方法的實際效果:

import java.io.IOException;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.node.ObjectNode;

class UserDeserialiser extends JsonDeserializer<User>
{
    @Override
    public User deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonProcessingException
    {
        System.out.println("Deserializing User...");

        ObjectNode node = jp.getCodec().readTree(jp);

        User user = new User();
        user.setFirstName(node.get("firstName").asText());
        user.setLastName(node.get("lastName").asText());

        JsonNode addressNode = node.get("address");
        if (addressNode != null)
        {
            JsonParser parser = addressNode.traverse();
            parser.setCodec(jp.getCodec());
            Address address = parser.readValueAs(Address.class);
            user.setAddress(address);
        }
        return user;
    }
}

class AddressDeserialiser extends JsonDeserializer<Address>
{
    @Override
    public Address deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException, JsonProcessingException
    {
        System.out.println("Deserializing Address...");

        ObjectNode node = jp.getCodec().readTree(jp);

        Address address = new Address();
        address.setStreetName(node.get("streetName").asText());
        address.setPostCode(node.get("postCode").asText());

        JsonNode addressTypeNode = node.get("addressType");
        if (addressTypeNode != null)
        {
            JsonParser parser = addressTypeNode.traverse();
            parser.setCodec(jp.getCodec());
            Address.AddressType addressType = 
                parser.readValueAs(Address.AddressType.class);
            address.setAddressType(addressType);
        }
        return address;
    }
}

public class NestedDeserializers
{
    public static void main(String[] args) throws IOException
    {

        User user = new User();
        user.setFirstName("A");
        user.setLastName("B");

        Address address = new Address();
        address.setStreetName("C");
        address.setPostCode("D");
        address.setAddressType(Address.AddressType.X);
        user.setAddress(address);

        ObjectMapper mapper = createObjectMapper();
        String jsonString = mapper.writeValueAsString(user);
        System.out.println("JSON string representation:\n" + jsonString);

        User readUser = mapper.readValue(jsonString, User.class);

        System.out.println("User     : " + user);
        System.out.println("Read user: " + readUser);
    }

    private static ObjectMapper createObjectMapper()
    {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
        SimpleModule module = new SimpleModule();
        module.addDeserializer(User.class, new UserDeserialiser());
        module.addDeserializer(Address.class, new AddressDeserialiser());
        mapper.registerModule(module);
        return mapper;
    }

}


//=============================================================================
// Dummy User/Address classes below

class User
{
    private String firstName;
    private String lastName;
    private Address address;

    public String getFirstName()
    {
        return firstName;
    }

    public void setFirstName(String firstName)
    {
        this.firstName = firstName;
    }

    public String getLastName()
    {
        return lastName;
    }

    public void setLastName(String lastName)
    {
        this.lastName = lastName;
    }

    public Address getAddress()
    {
        return address;
    }

    public void setAddress(Address address)
    {
        this.address = address;
    }

    @Override
    public String toString()
    {
        return "User [firstName=" + getFirstName() + ", lastName="
            + getLastName() + ", address=" + getAddress() + "]";
    }

}

class Address
{
    enum AddressType
    {
            X, Y;
    }

    private String streetName;
    private String postCode;
    private AddressType addressType;

    public String getStreetName()
    {
        return streetName;
    }

    public void setStreetName(String streetName)
    {
        this.streetName = streetName;
    }

    public String getPostCode()
    {
        return postCode;
    }

    public void setPostCode(String postCode)
    {
        this.postCode = postCode;
    }

    public AddressType getAddressType()
    {
        return addressType;
    }

    public void setAddressType(AddressType addressType)
    {
        this.addressType = addressType;
    }

    @Override
    public String toString()
    {
        return "Address [streetName=" + getStreetName() + ", postCode="
            + getPostCode() + ", addressType=" + getAddressType() + "]";
    }

}

暫無
暫無

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

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