Efter flere dages research har jeg fundet en løsning.
DutyBlockCodec afhænger af LocalDateCodec (som jeg oprettede) for at indkode/afkode. Denne afhængighed tilfredsstilles ikke blot ved at tilføje de to codecs til det samme codec-register. Løsningen er at sende et CodecRegistry objekt, der indeholder codecs, der DutyBlockCodec afhænger af (f.eks. et CodecRegistry indeholdende LocalDateCodec ) til DutyBlockCodec 's konstruktør, som er gemt som en medlemsvariabel. For at bruge LocalDateCodec for at kode bruger jeg EncoderContext.encodeWithChildContext() metode, der sender codec, writer og element til indkodning. Derudover skriver jeg individuelle felter i stedet for at skrive et Document som en String (som i min originale kode). Således DutyBlock codec ender med at se sådan her ud:
public class DutyBlockCodec implements Codec<DutyBlock> {
private final CodecRegistry codecRegistry;
public DutyBlockCodec(final CodecRegistry codecRegistry) {
this.codecRegistry = codecRegistry;
}
@Override
public void encode(BsonWriter writer, DutyBlock t, EncoderContext ec) {
writer.writeStartDocument();
Codec dateCodec = codecRegistry.get(LocalDate.class);
writer.writeName("startDate");
ec.encodeWithChildContext(dateCodec, writer, t.getStartDate());
writer.writeName("endDate");
ec.encodeWithChildContext(dateCodec, writer, t.getEndDate());
writer.writeName("blockLength");
writer.writeInt32(t.getBlockLength());
writer.writeName("pointValue");
writer.writeDouble(t.getPointValue());
//Writing ArrayList of RAs
writer.writeName("assigned");
writer.writeStartArray();
for (Ra ra : t.getRasOnDuty()) {
Codec raCodec = codecRegistry.get(Ra.class);
ec.encodeWithChildContext(raCodec, writer, ra);
}
writer.writeEndArray();
writer.writeEndDocument();
}
@Override
public Class<DutyBlock> getEncoderClass() {
return DutyBlock.class;
}
@Override
public DutyBlock decode(BsonReader reader, DecoderContext dc) {
reader.readStartDocument();
Codec<LocalDate> dateCodec = codecRegistry.get(LocalDate.class);
reader.readName();
LocalDate startDate = dateCodec.decode(reader, dc);
reader.readName();
LocalDate endDate = dateCodec.decode(reader, dc);
reader.readName();
int blockLength = reader.readInt32();
reader.readName();
double pointValue = reader.readDouble();
//Reading ArrayList of RAs
reader.readName();
Codec<Ra> raCodec = codecRegistry.get(Ra.class);
ArrayList<Ra> rasOnDuty = new ArrayList<>();
reader.readStartArray();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
rasOnDuty.add(raCodec.decode(reader, dc));
}
reader.readEndArray();
reader.readEndDocument();
return new DutyBlock(startDate, endDate, blockLength, pointValue, rasOnDuty);
}
}
DutyBlockCodec afhænger af et andet codec, og kræver derfor et CodecRegistry skal videregives til sin konstruktør. Selvom jeg tror, det er muligt at oprette et CodecRegistry med LocalDateCodec , så send dette som et argument til DutyBlockCodec 's constructor, og opret derefter endnu et CodecRegistry indeholdende både LocalDateCodec og DutyBlockCodec , dette er ret forvirrende, og MongoDB giver en funktionalitet, CodecProvider for at lette denne proces.
Brug af CodecProvider interface, skrev jeg en DutyBlockCodecProvider
public class DutyBlockCodecProvider implements CodecProvider {
@Override
public <T> Codec<T> get(Class<T> type, CodecRegistry cr) {
if (type == DutyBlock.class) {
return (Codec<T>) new DutyBlockCodec(cr);
}
return null;
}
}
Jeg tilføjede disse CodecProviders til MongoDB-klienten ved hjælp af CodecRegistries.fromProviders() metode.
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
CodecRegistries.fromCodecs(new LocalDateCodec()),
CodecRegistries.fromProviders(
new RaCodecProvider(),
new DutyBlockCodecProvider(),
new ScheduledDutyCodecProvider()),
MongoClient.getDefaultCodecRegistry());
MongoClientOptions options = MongoClientOptions.builder()
.codecRegistry(codecRegistry).build();
mongoClient = new MongoClient(new ServerAddress(), options);
db = mongoClient.getDatabase("DutySchedulerDB");
Min kildekode til dette projekt kan findes på https://github.com/desrepair/DutySchedulerJeg er åben for at besvare alle spørgsmål, folk måtte have.