反序列化使用自定义 getter 创建的 JSON 并使用 Jackson 解包对象

Deserialize JSON created using custom getter and unwrapped object using Jackson

提问人:Anho 提问时间:11/10/2023 更新时间:11/18/2023 访问量:73

问:

这是 Jackson 自定义 getter 答案的后续问题。

该解决方案有效并创建正确的 JSON。问题在于反序列化。我有一个未包装的对象,其中包含一些未在 JSON 中显示的属性,而是被新属性替换(例如 firstname+surname => name)。

这被正确地序列化为

{"age":22,"name":"Alex Doe"}

这个类是不能编辑的,所以我们依赖 mixin。

反序列化的问题是,在 之前调用,可能是因为属性在子对象之前被反序列化。这迫使我在 .当使用仅包含 age 的 -object 反序列化 age 时,此 -object 将被覆盖:PersonSerializer.setFullname()PersonSerializer.setPerson()PersonPersonSerializerObjectMapperPersonPerson

firstName: null, surname: null, age: 22

我可以在调用时存储并填充它,但这感觉不正确。fullnamesetFullname()personsetPerson()

解决这个问题的正确方法是什么?

法典:

public final class Person {

    private String firstName;
    private String surname;
    private int age;

    public Person() {
        super();
    }

    Person(final String firstName, final String surname, final int age) {
        super();
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
    }
 //getter and setter
}

序列化助手和基于答案的 mixin:

public class PersonSerializer {

    private Person person;

    public PersonSerializer() {
        super();
        person = new Person(); //needed, otherwise NPE in setFullname()
    }

    @JsonUnwrapped
    Person getPerson() {
        return person;
    }

    //customer getter to join firstname and surname
    @JsonGetter("name")
    String fullName() {
        return person.getFirstName() + " " + person.getSurname();
    }

    @JsonSetter("name")
    public void setFullname(final String fullName) {
        final String[] s = fullName.split(" ");
        person.setFirstName(s[0]);
        person.setSurname(s[1]);
    }

    public void setPerson(Person p) {
        person = p;
    }
}

abstract class PersonMixin {

    @JsonIgnore String firstName;
    @JsonIgnore String surname;
}

测试代码:

public static void main(String[] args)

        throws JsonProcessingException {

        final ObjectMapper mapper = new ObjectMapper().addMixIn(Person.class, PersonMixin.class);
        mapper.setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.ANY);
        final PersonSerializer alex = new PersonSerializer();
        alex.setPerson(new Person("Alex", "Doe", 22));
        final String s = mapper.writeValueAsString(alex);
        out.println(s);

        final Person newAlex = mapper.readValue(s, PersonSerializer.class).getPerson();
        out.println(String.format(
            "firstName: %s, surname: %s, age: %d",
            newAlex.getFirstName(),
            newAlex.getSurname(),
            newAlex.getAge()
        ));
    }

我搜索了示例、文档和 StackOverflow,但无济于事。

java json jackson json 反序列化

评论


答:

0赞 Ahmed Mera 11/13/2023 #1

您可以尝试此解决方案,它工作正常: 你只需要这个人就可以得到你想要的东西

public final class Person {

    private String firstName;
    private String surname;
    private int age;

    public Person() {
        super();
    }

    Person(final String firstName, final String surname, final int age) {
        super();
        this.firstName = firstName;
        this.surname = surname;
        this.age = age;
    }
 //getter and setter





    public static void main(String[] args) throws JsonProcessingException {

        final ObjectMapper mapper = new ObjectMapper();
        final Person alex = new Person("Alex", "Doe", 22);
        final String s = mapper.writeValueAsString(alex);
        System.out.println(s);

        final Person newAlex = mapper.readValue(s, Person.class);

        System.out.println(String.format(
                "firstName: %s, surname: %s, age: %d",
                newAlex.getFirstName(),
                newAlex.getSurname(),
                newAlex.getAge()
        ));
    }
}

输出为:

{"firstName":"Alex","surname":"Doe","age":22}
firstName: Alex, surname: Doe, age: 22

让我知道

评论

0赞 Anho 11/16/2023
谢谢。但是我想要一个扁平化的 JSON 作为结果,其中包含三个属性并且没有冗余属性,这就是我添加@JsonUnwrapped
0赞 Ahmed Mera 11/17/2023
在这种情况下,我将修改我的响应以获取三个属性。修改后再次查看 Ansower
0赞 Ahmed Mera 11/17/2023
尝试一下,让我知道
0赞 Anho 11/20/2023
正如我在问题中所写的:我想要 JSON,而不是 .如果您无法提供帮助,请停止。{"age":22,"name":"Alex Doe"}{"firstName":"Alex","surname":"Doe","age":22}
0赞 Paul Marcelin Bejan 11/18/2023 #2

我认为你的代码可以更简单: 你需要的是一个 Wrapper of Person 类,因为你无法编辑它。

人:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {

    private String firstName;
    
    private String surname;
    
    private int age;

}

人员包装

public class PersonWrapper extends Person {
     
    private String name;
    
    public PersonWrapper() {
        super();
    }

    public PersonWrapper(String firstName, String surname, int age) {
        super(firstName, surname, age);
        name = getName();
    }

    public String getName() {
        this.name = getFirstName() + " " + getSurname();
        return name;
    }
    
    public void setName(final String name) {
        final String[] s = name.split(" ");
        setFirstName(s[0]);
        setSurname(s[1]);
    }
    
}

PersonMixIn:

public abstract class PersonMixIn {

    @JsonIgnore 
    String firstName;
    
    @JsonIgnore 
    String surname;
    
}

测试:

public class Application {

    public static void main(String[] args) throws JsonProcessingException {
        
        final ObjectMapper mapper = new ObjectMapper().addMixIn(PersonWrapper.class, PersonMixIn.class);
        final PersonWrapper alex = new PersonWrapper("Alex", "Doe", 22);
        final String s = mapper.writeValueAsString(alex);
        System.out.println(s);

        final Person newAlex = mapper.readValue(s, PersonWrapper.class);
        System.out.println(String.format(
            "firstName: %s, surname: %s, age: %d",
            newAlex.getFirstName(),
            newAlex.getSurname(),
            newAlex.getAge()
        ));
        
    }

}

结果:

序列化: {“age”:22,“name”:“Alex Doe”}

反序列化:名字:Alex,姓氏:Doe,年龄:22

评论

0赞 Anho 11/20/2023
-class 是最终的,我无法从它扩展。Person
0赞 Paul Marcelin Bejan 11/20/2023
对不起,我没有看到。我会尽快改变答案。