【问题标题】:Jackson 2: Ignore transient field only when serialisingJackson 2:仅在序列化时忽略瞬态字段
【发布时间】:2020-02-16 03:14:37
【问题描述】:

我在 JAX-RS 应用程序中使用 Jackson v2,我正在尝试确定是否可能 配置“ObjectMapper”以删除带有瞬态修饰符的字段,但仅在序列化期间。

这是一个 DTO 来说明我的用例(省略了 getter 和 setter)

public class User {
    private String email;
    private transient String password;
}

考虑到上述 DTO,我想要一个对象映射器 序列化时的密码字段,反序列化时包含它。

关于瞬态,我唯一能找到的是:

MapperFeature.PROPAGATE_TRANSIENT_MARKER

但该配置与我的要求无关。

P.S - 不使用注释,因为 DTO 不与任何库耦合,另外 我不一定能控制它们。

【问题讨论】:

  • 我不明白,如果你不序列化属性A,那么A会反序列化什么,如果你包含它呢?
  • stackoverflow.com/questions/57184389/… - 我所指的用例与该线程中的用例相同(7 年前)。我希望有一个不涉及注释的解决方案。
  • 您所描述的内容听起来不像链接的问题。那里接受的答案不使用注释进行序列化/反序列化。那里的注解有@Override@SuppressWarnings@Test。而你没有回答我的问题。
  • 当我说的是带有字段电子邮件和密码的传入 JSON 应构造为用户实例,并填充其电子邮件和密码 - 将用户实例转换回JSON,我希望忽略瞬态字段。 (同样的行为应该适用于任何类型,而不仅仅是用户。)

标签: java serialization jackson2


【解决方案1】:

不知道,看起来像transient 属性修饰符加上PROPAGATE_TRANSIENT_MARKER 就可以了。反序列化是直截了当的。不过,在序列化过程中有一些fuss with the transient marker。您需要为字段提供 getter,否则您将遇到异常“无法识别的字段...未标记为可忽略”。

针对其他要求,我添加了一个使用 jackson mixins 的版本。请注意,mixin 版本生成带有空密码字段的 json,而 PROPAGATE_TRANSIENT_MARKER 版本根本不生成任何字段。

PROPAGATE_TRANSIENT_MARKER 版本

public class SerializeDeserializeAttributes {
    private final ObjectMapper mapper = new ObjectMapper();

public <T> T fromJson(String json, Class<T> c) throws IOException {
    synchronized (mapper) {
        mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, false);
        return mapper.readValue(json, c);
    }
}

public String toJson(Object o) throws JsonProcessingException {
    synchronized (mapper) {
        mapper.configure(MapperFeature.PROPAGATE_TRANSIENT_MARKER, true);
        return mapper.writeValueAsString(o);
    }
}

    private static final String jsonFull = "{\"name\":\"A\",\"email\":\"a@a\",\"password\":\"a\",\"width\":1,\"height\":1}";
    private static final String jsonPartial = "{\"name\":\"A\",\"email\":\"a@a\",\"width\":1,\"height\":1}";
    private static final User user = new User("A", "a@a", "a", 1, 1);

    @Test
    public void serializeDeserialize() throws IOException {
        assertEquals(user, fromJson(jsonFull, User.class));
        assertEquals(jsonPartial, toJson(user));
        assertEquals(user, fromJson(jsonFull, User.class));
        assertEquals(jsonPartial, toJson(user));
    }
}

混音版

public class SerializeDeserializeAttributesMixin {

    public abstract class UserMixin {
        @JsonSerialize(using = PwdSerializer.class)
        transient String password;
    }

    static class PwdSerializer extends StdSerializer<String> {

        public PwdSerializer() {
            this(String.class);
        }

        private PwdSerializer(Class<String> t) {
            super(t);
        }

        @Override
        public void serialize(String s, JsonGenerator jg, SerializerProvider sp) throws IOException {
            jg.writeString("");
        }
    }

    private static final String jsonFull = "{\"name\":\"A\",\"email\":\"a@a\",\"password\":\"a\",\"width\":1,\"height\":1}";
    private static final String jsonPartialMixin = "{\"name\":\"A\",\"email\":\"a@a\",\"password\":\"\",\"width\":1,\"height\":1}";
    private static final User user = new User("A", "a@a", "a", 1, 1);
    private static final ObjectMapper mapperMixin = new ObjectMapper();

    static {
        mapperMixin.addMixIn(User.class, UserMixin.class);
    }


    @Test
    public void serializeDeserializeUsingMixin() throws IOException {
        assertEquals(user, mapperMixin.readValue(jsonFull, User.class));
        assertEquals(jsonPartialMixin, mapperMixin.writeValueAsString(user));
    }

}

这就是 User 类。

class User {
    private String name;
    private String email;
    private transient String password;
    private int width;
    private int height;

    public User() {
    }

    User(String name, String email, String password, int width, int height) {
        this.name = name;
        this.email = email;
        this.password = password;
        this.width = width;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    public String getPassword() {
        return password;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Float.compare(user.width, width) == 0 &&
                Float.compare(user.height, height) == 0 &&
                Objects.equals(name, user.name) &&
                Objects.equals(email, user.email) &&
                Objects.equals(password, user.password);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, email, password, width, height);
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", email='" + email + '\'' +
                ", password='" + password + '\'' +
                ", width=" + width +
                ", height=" + height +
                '}';
    }
}

【讨论】:

  • 发布的代码有效的唯一原因是,“fromJson”方法没有重复使用相同的 objectMapper 实例——我担心创建多个实例是无操作的我。
  • 建筑师??‍♂️。我想我只会使用mixins。我不能标记这是一个公认的答案,因为它不是我认为正确的答案。如果您将帖子更改为包含 mixins,我会接受。
  • 我想这确实回答了这个问题 - 但不是很安全:) 无论哪种方式,当与 JAX-RS 和 ContextResolver 提供程序结合使用时,它仍然不可行。我会接受这个,因为我的问题没有提到提到的要求。
  • 我添加了jackson mixin版本。
猜你喜欢
  • 1970-01-01
  • 2018-07-21
  • 2012-02-01
  • 2016-07-26
  • 1970-01-01
  • 1970-01-01
  • 2012-02-01
  • 2019-10-22
  • 1970-01-01
相关资源
最近更新 更多