java - 使用 MongoDB、Jackson 和 MongoJack 的自定义序列化程序

标签 java json mongodb serialization jackson

我有一个类,在序列化时,应该在其位置序列化其成员之一。我的类(class)是:

@JsonSerialize(using = MyClassSerializer.class)
public class MyClass implements Serializable {

    /**
     * A default ID for this class for serialization.
     */
    private static final long serialVersionUID = 1L;

    /**
     * A member of this object.
     */
    private final OtherClass otherClass;

    ...

    /**
     * Returns the instance of the member object.
     * 
     * @return The instance of the member object.
     */
    public OtherClass getOtherClass() {
        return otherClass;
    }
}

为此,我创建了一个非常简单的自定义序列化程序:

public class MyClassSerializer extends JsonSerializer<MyClass> {
    /**
     * Serializes only the OtherClass field.
     */
    @Override
    public void serialize(
        final MyClass myClass,
        final JsonGenerator generator,
        final SerializerProvider provider)
        throws IOException, JsonProcessingException {

        // Write the schema.
        generator.writeObject(myClass.getOtherClass());
    }
}

这是执行此类操作的最简单(而且我相信也是最正确)的方法。即使我愿意,为 OtherClass 编写自定义序列化程序也会非常复杂,因为它是一个抽象根类。然而,这可以通过 Jackson 完成,并添加一些注释:

@JsonTypeInfo(
    use = Id.NAME,
    include = As.PROPERTY,
    property = OtherClass.JSON_KEY_TYPE,
    defaultImpl = OtherClassDefault.class)
@JsonSubTypes({
    @JsonSubTypes.Type(
        value = SubOtherClass1.class,
        name = SubOtherClass1.TYPE_ID),
    @JsonSubTypes.Type(
        value = SubOtherClass2.class,
        name = SubOtherClass2.TYPE_ID),
    @JsonSubTypes.Type(
        value = SubOtherClass3.class,
        name = SubOtherClass3.TYPE_ID),
    @JsonSubTypes.Type(
        value = SubOtherClass4.class,
        name = SubOtherClass4.TYPE_ID),
    @JsonSubTypes.Type(
        value = SubOtherClass5.class,
        name = SubOtherClass5.TYPE_ID) })
@JsonAutoDetect(
    fieldVisibility = Visibility.DEFAULT,
    getterVisibility = Visibility.NONE,
    setterVisibility = Visibility.NONE,
    creatorVisibility = Visibility.DEFAULT)
public abstract class OtherClass implements Serializable {
    ...
}

我已经使用 Jackson 对 MyClass 的实例进行序列化和反序列化进行了测试,它完全按预期工作。

我的应用程序代码有点复杂。我有一个 ContainerClass,它有一个类型为 MyClass 的成员。我尝试通过 MongoJack 序列化 ContainerClass 的实例:

// Get the authentication token collection.
JacksonDBCollection<ContainerClass, Object> collection =
    JacksonDBCollection
        .wrap(
            MongoBinController
                .getInstance()
                .getDb()
                .getCollection(COLLECTION_NAME),
            ContainerClass.class);

// Save it.
collection.insert(container);

但是,我收到以下错误:

...
Caused by: java.lang.IllegalArgumentException: can't serialize class my.package.MyClass
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:270)
    ...

如果我从 MyClass 中删除 @JsonSerialize,我可以让它工作,但是这会导致整个 MyClass 实例被序列化,这不是我想要的。这让我几乎可以肯定问题出在我的自定义序列化程序中,但我不确定我应该如何编写它。

提前谢谢你。

最佳答案

一个可能有帮助的快速说明:当使用多态类型时,调用的方法将是:

serializeWithType(...)

而不是serialize(...)。所以你需要实现那个方法;通常它会像这样简单:

typeSer.writeTypePrefixForObject(value, jgen);
// implement actual content serialization, or delegate here:
this.serialize(...);
typeSer.writeTypeSuffixForObject(value, jgen);

但您可能想看看标准的 Jackson 序列化程序。唯一真正的区别是,虽然 serialize 需要直接输出 START_OBJECT、END_OBJECT,但在这里我们必须要求 TypeSerializer 添加它们。这是必要的,因为包含 type id 实际上可能会改变这些(我可以详细说明这一点,但现在这应该足够了)。

但是:这里可能有更简单的解决方案。如果您可以在要使用的成员上添加 @JsonValue 注释而不是整个对象(直接或通过混合),那应该可以解决问题:

@JsonValue
public OtherClass getOtherClass()...

如果你需要反序列化,你可以使用@JsonCreator,比如:

@JsonCreator
public MyClass(OtherClass surrogate) { ... }

关于java - 使用 MongoDB、Jackson 和 MongoJack 的自定义序列化程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19037944/

相关文章:

java - 在 recyclerview 中访问 JSON 数组中的项目成员

jquery - 如何通过ajax调用获取JSON数据

javascript - 已部署的图像共享

java - 如何在 Java 中合并和转换两种不同类型的 map ?

java - 读取 CA 证书私钥以签署证书

java - 在大型 Java 应用程序中标准化日志记录的方法

mongodb - 蒙哥 : query by key one level deep

java - 如何在 docker 容器中运行瘦 jar

java - 是否可以设置 Jackson 以便将未命名的包装器对象排除到 API 返回的 JSON 数组中?

mongodb - Mongoose.js instance.save() 回调未触发