简体   繁体   English

Jackson 链自定义解串器

[英]Jackson chain custom deserializers

If you have a class User :如果您有一个类User

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

And a class Address respectively:和一个类Address分别:

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

And custom Jackson deserializers for both, is there a good way to link them?以及为两者定制的 Jackson 反序列化器,是否有链接它们的好方法? eg例如

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
    }
}

Similarly in the Address deserialiser, is it possible to delegate to the default one to handle the enum (as it might have custom mappings)?同样在地址反序列化器中,是否可以委托默认的来处理枚举(因为它可能具有自定义映射)?

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?
    }
}

I had the same requirement a while ago, and figured out a solution.不久前我也有同样的需求,并想出了一个解决方案。 I don't think it's a "nice" solution, because it's a bit clumsy, but maybe this encourages someone to write a better answer.我不认为这是一个“不错”的解决方案,因为它有点笨拙,但也许这会鼓励某人写出更好的答案。 That would be great.那很好啊。


As mentioned in a comment, this can usually be solved by using annotations.正如评论中提到的,这通常可以通过使用注释来解决。 Specifically, the @JacksonDeserialize annotations.具体来说, @JacksonDeserialize注释。

But if (for whatever reason - and there are many possible reasons for that) the use of annotations is not desired, it is necessary to explicitly create a parser for the relevant subtree of the JSON tree.但是,如果(无论出于何种原因 - 并且有很多可能的原因)不希望使用注释,则有必要为 JSON 树的相关子树显式创建解析器。 This will pick up either the default deserializers or the custom deserializers that have been registered for the respective type in the module of the object mapper.这将选择默认解串器已在对象映射器模块中为相应类型注册的自定义解串器。

The relevant part/pattern referring to your example, namely to the point that contained the ???参考您的示例的相关部分/模式,即包含??? question marks, is this:问号,这是:

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);
}

Here is a MCVE showing this approach in action:这是一个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