Java 使用Jackson以两种不同的方式序列化一个类

Java 使用Jackson以两种不同的方式序列化一个类,java,mongodb,jackson,pojo,mongo-jackson-mapper,Java,Mongodb,Jackson,Pojo,Mongo Jackson Mapper,在我们的一个项目中,我们使用JavaWebApp与MongoDB实例对话。在数据库中,我们使用DBRefs跟踪一些对象关系。我们使用jackson(使用mongodbjackson映射器)对POJO对象进行反序列化 然而,我们使用相同的POJO然后(反)序列化到外部世界,在那里我们的前端处理JSON的呈现 现在,我们需要一种外部世界的序列化方法来包含来自DBRef的引用对象(以便UI可以显示完整的对象),而我们显然希望将DBRef写入数据库,而不是整个对象 现在我编写了一些未经测试的静态嵌套类代

在我们的一个项目中,我们使用JavaWebApp与MongoDB实例对话。在数据库中,我们使用
DBRefs
跟踪一些对象关系。我们使用jackson(使用mongodbjackson映射器)对POJO对象进行反序列化

然而,我们使用相同的POJO然后(反)序列化到外部世界,在那里我们的前端处理JSON的呈现

现在,我们需要一种外部世界的序列化方法来包含来自
DBRef
的引用对象(以便UI可以显示完整的对象),而我们显然希望将
DBRef
写入数据库,而不是整个对象

现在我编写了一些未经测试的静态嵌套类代码:

public static class FooReference {
    public DBRef<Foo> foo;

    // FIXME how to ensure that this doesn't go into the database?
    public Foo getFoo() {
        return foo.fetch();
    }
}
公共静态类引用{
公共DBRef foo;
//修复如何确保这不会进入数据库?
公共Foo getFoo(){
返回foo.fetch();
}
}

理想情况下,我希望有一种方法对其进行注释,这样我就可以(反)序列化它,可以使用getFoo()结果,也可以不使用getFoo()结果,这可能取决于某些配置对象。这可能吗?您认为有更好的方法吗?

使用自定义的
JSONSerializer
并在
序列化方法中应用您的逻辑:

public static class FooReference {
    public DBRef<Foo> foo;

    @JsonSerialize(using = CustomSerializer.class)
    public Foo getFoo() {
        return foo.fetch();
    }
}

public class CustomSerializer extends JsonSerializer<Object> {
   public void serialize(Object value, JsonGenerator jgen, SerializerProvider provider)
       throws IOException, JsonProcessingException {
     // jgen.writeObjectField ...
   }
}
公共静态类引用{
公共DBRef foo;
@JsonSerialize(使用=CustomSerializer.class)
公共Foo getFoo(){
返回foo.fetch();
}
}
公共类CustomSerializer扩展JsonSerializer{
公共void序列化(对象值、JsonGenerator jgen、SerializerProvider提供程序)
抛出IOException、JsonProcessingException{
//jgen.WriteObject字段。。。
}
}

从选项来看,似乎只有在将给定的
视图
传递给用于序列化的
对象映射器
时,才可以对属性进行注释以显示。因此,您可以编辑该类:

public static class FooReference {
    public DBRef<Foo> foo;

    @JsonView(Views.WebView.class)
    public Foo getFoo() {
        return foo.fetch();
    }
}
然后在创建具有正确视图的配置后序列化:

SerializationConfig conf = objectMapper.getSerializationConfig().withView(Views.WebView.class);
objectMapper.setSerializationConfig(conf);
然后将其序列化。使用MongoDB包装序列化时不指定视图将意味着该方法将被忽略。默认情况下,不带JsonView注释的属性是序列化的,您可以通过指定以下内容来更改此行为:

objectMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);
更多信息可用


事实证明,还有其他替代方案:有一些替代方案可以让您在不修改类本身的情况下重写(反)类部分的序列化行为,而从Jackson 2.0(最新版本)开始,也有一些替代方案。

我如何做到这一点,它如何解决这个问题?这是我的代码,所以我可以做任何事情,但你的评论不清楚,谷歌也没有帮助,对不起。“transient”是一个java关键字,表示字段不应序列化/持久化-呃,这是一个字段修饰符。这是一个方法。mongodb对方法有瞬时的或非持久的注释吗?Mongo本身有驱动程序(处理类似于普通映射的对象),这些驱动程序已通过各种不同的方式进行扩展/替换/包装,以提供POJO支持。原来Morphia有一个瞬态注释和一个未存储的注释,但我使用的是mongo jackson mapper。谷歌搜索显示Jackson支持序列化视图,mongo Jackson mapper允许您指定要使用的视图,所以这似乎是可行的。谢谢你的指点!这个调用不是无条件的吗?这将是次优的,因为它意味着一个数据库请求。此外,据我所知,序列化程序将使用类ref构造,因此它没有上下文可以推断是否序列化对象。所以我需要依赖某种静态标志,它存在于我在序列化/反序列化之前/之后旋转的同一个线程中?这看起来很脆弱。是的,我误解了你的问题。但是,您可以不返回
foo.fetch()
,而是返回一个包装器,在
序列化
中,该包装器将确定您是否需要发出数据库请求或序列化字段。关于我提出的第一点,这听起来不错。关于第二个:理想情况下,我不希望模型/POJO中有任何关于模型外发生的事情的数据(即,“我是如何被序列化的”)。也就是说,在调用(反)序列化时,我更愿意从两种序列化方法中选择一种。这有意义吗?使用您描述的方法是否可行?(投票赞成指出JsonSerialize,无论如何,但目前还不确定它是否是这个问题的解决方案)我明白了,使用这种方法是可能的,但它确实会以某种方式将序列化机制与模型耦合起来。我在Jackson中知道的唯一一种允许您这样做的机制实际上是
JSONSerializer
,因此我担心您必须将自定义逻辑放在其中。
objectMapper.configure(SerializationConfig.Feature.DEFAULT_VIEW_INCLUSION, false);