I have an existing object that I want to serialize in MongoDB using Java + POJO codec. For some reason the driver tries to create an instance of an enum instead of using 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
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 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. 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.