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.