简体   繁体   English

使用MongoDB,Jackson和MongoJack的自定义序列化器

[英]Custom Serializer with MongoDB, Jackson, and MongoJack

I have a class that, when serialized, should serialize one of its members in its place. 我有一个类,当进行序列化时,应该在其位置序列化其成员之一。 My class is: 我的课是:

@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;
    }
}

To accomplish this, I created a very simple custom serializer: 为此,我创建了一个非常简单的自定义序列化程序:

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());
    }
}

This is the easiest (and, I believe, most correct) way to do something like this. 这是做这样的事情的最简单(也是最正确的方法)。 Even if I wanted to, writing a custom serializer for OtherClass would be extremely complex because it is an abstract root class. 即使我愿意,为OtherClass编写自定义序列化程序也将非常复杂,因为它是抽象的根类。 This can be accomplished through Jackson, however, with a few annotations: 可以通过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 {
    ...
}

I have tested this using Jackson to serialize and deserialize instances of MyClass, and it works exactly as intended. 我已经使用Jackson进行了序列化和反序列化MyClass实例的测试,它完全可以按预期工作。

My application code is a little more complicated. 我的应用程序代码稍微复杂一些。 I have a ContainerClass that has a member of type MyClass . 我有一个具有MyClass类型成员的ContainerClass I attempt to serialize an instance of ContainerClass through MongoJack: 我尝试通过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);

However, I receive the following error: 但是,我收到以下错误:

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

I can get it to work if I remove the @JsonSerialize from MyClass , however this results in the entire MyClass instance being serialized, which is not what I want. 如果从MyClass删除@JsonSerialize ,我可以使它工作,但是这导致整个MyClass实例被序列化,这不是我想要的。 This makes me almost sure that the problem lies in my custom serializer, but I am not sure how else I am supposed to write it. 这几乎使我确定问题出在我的自定义序列化程序中,但是我不确定应该如何编写它。

Thank you in advance. 先感谢您。

One quick note that may help: when using polymorphic types, method called will be: 快速说明可能会有所帮助:使用多态类型时,调用的方法将是:

serializeWithType(...)

and not serialize(...) . 而不是serialize(...) So you will need to implement that method; 因此,您将需要实现该方法。 usually it will be something as simple as: 通常它会很简单:

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

but you may want to have a look at standard Jackson serializers. 但您可能想看看标准的Jackson序列化器。 The only real distinction is that whereas serialize needs to output START_OBJECT, END_OBJECT directly, here we have to ask TypeSerializer to add those. 唯一真正的区别是,虽然serialize需要直接输出START_OBJECT,END_OBJECT,但在这里我们必须要求TypeSerializer添加它们。 This is necessary because type id inclusion may actually change these (I can elaborate on this, but for now that should be enough). 这是必需的,因为type id包含实际上可能会更改这些内容(我可以对此进行详细说明,但现在就足够了)。

However: there may be much easier solution here. 但是:这里可能有更简单的解决方案。 If you can add @JsonValue annotation on member you want to use instead of whole object (either directly, or via mix-in), that should do the trick: 如果可以在要使用的成员上添加@JsonValue批注而不是整个对象(直接或通过混合),则可以实现此目的:

@JsonValue
public OtherClass getOtherClass()...

and if you need to deserialize, you can use @JsonCreator like: 如果需要反序列化,则可以使用@JsonCreator例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM