【问题标题】:Jackson only interface field deserializationJackson 唯一接口字段反序列化
【发布时间】:2018-04-18 13:45:07
【问题描述】:

是否可以只反序列化接口中的字段

public interface B {
    String getB();
}

public interface A {
    String getA();
}

public class Impl implements A, B {

    @Override
    public String getA() {
        return "stringA";
    }

    @Override
    public String getB() {
        return "stringB";
    }

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        A implA = new Impl();
        B implB = new Impl();

        String jsonA = null;
        String jsonB = null;
        try {
            jsonA = mapper.writeValueAsString(implA);
            jsonB = mapper.writeValueAsString(implB);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(jsonA);
        System.out.println();
        System.out.println(jsonB);
    }
}

我的预期

接口A

{"a":"stringA"}

接口 B

{"b":"stringB"}

我得到的

{"a":"stringA","b":"stringB"}

{"a":"stringA","b":"stringB"}

一个接口可以用这个注解 @JsonSerialize(as=A.class),但它只适用于第一个接口。 @JsonSerialize 的输出是

{"a":"stringA"}

{"a":"stringA"}

【问题讨论】:

  • 我怀疑您的要求没有解决方案。即使使用自定义序列化程序,您也可以使用ABImplJsonSerializer 进行参数化,并且在任何情况下,由于writeValueAsString 不采用JsonSerializer 作为参数,因此您的代码不会不知道如何处理给定的 Impl 实例。
  • @ApfelPresse ...我已经更新了我的答案以给出一个工作示例。
  • 编写两个自定义 Jackson 序列化程序类。一个用于接口 A,一个用于接口 B。

标签: java json jackson


【解决方案1】:

查看 JsonIgnore 注释。

https://fasterxml.github.io/jackson-annotations/javadoc/2.7/com/fasterxml/jackson/annotation/JsonIgnore.html

更新

Jackson 的@JsonView 可能符合您的要求。下面是一些描述用例的好文章。

Jackson Change JsonIgnore Dynamically

http://www.baeldung.com/jackson-json-view-annotation

代码示例

public class Sandbox {

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        A implA = new Impl();
        B implB = new Impl();

        String jsonA = null;
        String jsonB = null;
        try {
            ObjectWriter jsonAWriter = mapper.writerWithView(A.class);
            jsonA = jsonAWriter.writeValueAsString(implA);

            ObjectWriter jsonBWriter = mapper.writerWithView(B.class);
            jsonB = jsonBWriter.writeValueAsString(implB);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(jsonA);
        System.out.println();
        System.out.println(jsonB);
    }

    public interface A {
        String getA();
    }

    public interface B {
        String getB();
    }

    public static class Impl implements A, B {

        @Override
        @JsonView(A.class)
        public String getA() {
            return "stringA";
        }

        @Override
        @JsonView(B.class)
        public String getB() {
            return "stringB";
        }
    }
}

输出:

{"a":"stringA"}

{"b":"stringB"}

【讨论】:

  • 这本身肯定不符合要求。
  • 感谢 Mena 的反馈 .. 我看错了问题,回答得太快了 ..
  • 没问题@ggolding。老实说,我怀疑没有解决方案,因为 OP 希望根据引用类型有条件地序列化。
  • 我怀疑您的更新仍然不适用于此案例。你试过了吗?
  • @Mena ...我已经更新了工作代码示例并按预期输出。
【解决方案2】:

根据多态性原则,没有办法做到这一点。下面是长证明和一些替代方法。

您的implAimplB 是对同一类型对象的引用。它们由同一个序列化程序序列化。它们同时是 A、B 和 Impl 的实例。序列化器方法无法找出您希望它序列化的类型。它只能使用.class(默认行为)检查真实类型。它还可以解析注释以找出您希望将其序列化为哪个类,并检查它是否真的是该类型的实例。只能这样了。

虽然它也可以使用一些反射来查找有关对象及其类的一些附加信息,但是没有关于您在 main() 方法中声明的变量类型的信息。

变量类型通常在运行时不可用,它是编译时检查。虽然,在 Java 世界中,它可能在 JVM 中的某个地方可用,或者作为调试信息,我不确定。但绝对没有从可调用方法到调用方法的编程访问。

因此,您可以使用@JsonSerialize(as=A.class) 注释来选择一种使用单个序列化器序列化单个类的方法。

或者您可以实现自己的序列化程序,它将基于一些繁忙逻辑使用不同的超类,但不基于多态性。

【讨论】:

    最近更新 更多