使用Java MongoDB驱动程序无法使用枚举读取或序列化POJO

时间:2018-03-25 15:36:35

标签: java mongodb serialization pojo

我有一个现有的对象,我想使用Java + POJO编解码器在MongoDB中进行序列化。出于某种原因,驱动程序尝试创建枚举的实例而不是使用valueOF:

org.bson.codecs.configuration.CodecConfigurationException: Failed to decode 'phase'. Failed to decode 'value'. Cannot find a public constructor for 'SimplePhaseEnumType'.
at org.bson.codecs.pojo.PojoCodecImpl.decodePropertyModel(PojoCodecImpl.java:192)
at org.bson.codecs.pojo.PojoCodecImpl.decodeProperties(PojoCodecImpl.java:168)
at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:122)
at org.bson.codecs.pojo.PojoCodecImpl.decode(PojoCodecImpl.java:126)
at com.mongodb.operation.CommandResultArrayCodec.decode(CommandResultArrayCodec.java:52)

枚举:

public enum SimplePhaseEnumType {

PROPOSED("Proposed"),
INTERIM("Interim"),
MODIFIED("Modified"),
ASSIGNED("Assigned");
private final String value;

SimplePhaseEnumType(String v) {
    value = v;
}

public String value() {
    return value;
}

public static SimplePhaseEnumType fromValue(String v) {
    for (SimplePhaseEnumType c: SimplePhaseEnumType.values()) {
        if (c.value.equals(v)) {
            return c;
        }
    }
    throw new IllegalArgumentException(v);
}}

使用枚举的类(仅显示相关字段):

public class SpecificPhaseType {

protected SimplePhaseEnumType value;
protected String date;

public SimplePhaseEnumType getValue() {
    return value;
}

public void setValue(SimplePhaseEnumType value) {
    this.value = value;
}}

我正在寻找一种方法来对类进行注释,以告诉驱动程序在遇到这些字段时使用不同的方法来序列化/反序列化这些字段。我知道如何在序列化/反序列化过程中跳过它们,但这并不能解决问题:

public class SpecificPhaseType {

@BsonIgnore
protected SimplePhaseEnumType value;

我可以查看的任何帮助(代码,文档)?我已经检查了PojoQuickTour.javaMongoDB Driver Quick Start - POJOsPOJOs - Plain Old Java Objects

谢谢!

- 圣何塞

1 个答案:

答案 0 :(得分:0)

我想出了要做什么,你首先需要编写一个自定义编解码器来读取和编写枚举作为一个字符串(如果你想节省空间,则序号是另一个选项,但字符串对我来说还不错):

package com.kodegeek.cvebrowser.persistence.serializers;

import com.kodegeek.cvebrowser.entity.SimplePhaseEnumType;
import org.bson.BsonReader;
import org.bson.BsonWriter;
import org.bson.codecs.Codec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;

public class SimplePhaseEnumTypeCodec implements Codec<SimplePhaseEnumType>{
    @Override
    public SimplePhaseEnumType decode(BsonReader reader, DecoderContext decoderContext) {
        return SimplePhaseEnumType.fromValue(reader.readString());
    }

    @Override
    public void encode(BsonWriter writer, SimplePhaseEnumType value, EncoderContext encoderContext) {
        writer.writeString(value.value());
    }

    @Override
    public Class<SimplePhaseEnumType> getEncoderClass() {
        return SimplePhaseEnumType.class;
    }
}

然后你需要注册新的编解码器,以便MongoDB可以使用你的类处理枚举:

/**
 * MongoDB could not make this any simpler ;-)
 * @return a Codec registry
 */
public static CodecRegistry getCodecRegistry() {
    final CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
    final CodecProvider pojoCodecProvider = PojoCodecProvider.builder().register(packages).build();
    final CodecRegistry cvePojoCodecRegistry = CodecRegistries.fromProviders(pojoCodecProvider);
    final CodecRegistry customEnumCodecs = CodecRegistries.fromCodecs(
            new SimplePhaseEnumTypeCodec(),
            new StatusEnumTypeCodec(),
            new TypeEnumTypeCodec()
    );
    return CodecRegistries.fromRegistries(defaultCodecRegistry, customEnumCodecs, cvePojoCodecRegistry);
}

Jackson使用@JsonSerializer / @JsonDeserializer等注释更容易注册自定义序列化器/反序列化器,而Mongo强制您处理注册表。没什么大不了的: - )

您可以查看完整的源代码here。希望这可以节省一些必须处理类似问题的人的时间。