简体   繁体   English

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

[英]Cannot read or serialize POJO with enumerations using Java MongoDB driver

I have an existing object that I want to serialize in MongoDB using Java + POJO codec. 我有一个现有对象,我想使用Java + POJO编解码器在MongoDB中进行序列化。 For some reason the driver tries to create an instance of an enum instead of using valueOF: 由于某种原因,驱动程序尝试创建枚举的实例,而不是使用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)

The enumeration: 枚举:

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

And the class the uses the enumeration (only showing the relevant fields): 并且该类使用枚举(仅显示相关字段):

public class SpecificPhaseType {

protected SimplePhaseEnumType value;
protected String date;

public SimplePhaseEnumType getValue() {
    return value;
}

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

I was looking for a way to maybe annotate the class to tell the driver to use a different method to serialize / deserialize those fields when they are encountered. 我正在寻找一种注释类的方法,以告知驱动程序在遇到这些字段时使用其他方法来序列化/反序列化这些字段。 I know how to skip them during the serialization / deserialization but that doesn't fix the problem: 我知道如何在序列化/反序列化期间跳过它们,但这不能解决问题:

public class SpecificPhaseType {

@BsonIgnore
protected SimplePhaseEnumType value;

Any help on where I could look (code, documentation)?. 对我的外观有任何帮助(代码,文档)? I already checked PojoQuickTour.java , MongoDB Driver Quick Start - POJOs and POJOs - Plain Old Java Objects 我已经检查过PojoQuickTour.javaMongoDB驱动程序快速入门 -POJO和POJO- 普通的旧Java对象

Thanks! 谢谢!

--Jose -乔斯

I figured out what to do, you first need to write a custom Codec to read and write the enum as a String (an ordinal is another option if you want to save space, but string was more than OK with me): 我弄清楚该怎么办,您首先需要编写一个自定义编解码器以将枚举作为字符串读取和写入(如果要节省空间,则序数是另一种选择,但是字符串对我来说还可以):

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

Then you need to register the new codec so MongoDB can handle the enum using your 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 makes it easier to register custom serializer/ deserializer with annotations like @JsonSerializer / @JsonDeserializer and while Mongo forces you to deal with the registry. Jackson使使用@JsonSerializer / @JsonDeserializer等注解注册自定义序列化器/反序列化器更加容易,而Mongo则迫使您处理注册表。 Not a big deal :-) 没有大碍 :-)

You can peek at the full source code here . 您可以在此处查看完整的源代码。 Hope this saves some time to anyone who has to deal with a similar issue. 希望这可以为需要处理类似问题的任何人节省一些时间。

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

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