Na een aantal dagen onderzoek heb ik een oplossing gevonden.
De DutyBlockCodec
hangt af van de LocalDateCodec
(die ik heb gemaakt) om te coderen / decoderen. Aan deze afhankelijkheid wordt niet voldaan door de twee codecs toe te voegen aan hetzelfde codec-register. De oplossing is om een CodecRegistry
. door te geven object dat de codecs bevat die DutyBlockCodec
hangt af van (bijvoorbeeld een CodecRegistry
met daarin de LocalDateCodec
) naar de DutyBlockCodec
's constructor, die wordt opgeslagen als een lidvariabele. Om de LocalDateCodec
. te gebruiken om te coderen, gebruik ik de EncoderContext.encodeWithChildContext()
methode, waarbij de codec, de schrijver en het te coderen element worden doorgegeven. Bovendien schrijf ik individuele velden in plaats van een Document
als een String
(zoals in mijn originele code). Dus de DutyBlock
codec ziet er uiteindelijk zo uit:
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
hangt af van een andere codec, en vereist dus een CodecRegistry
door te geven aan de constructeur. Hoewel ik geloof dat het mogelijk is om een CodecRegistry
. te maken met de LocalDateCodec
, geef dit dan als argument door aan DutyBlockCodec
's constructor, maak dan nog een CodecRegistry
met zowel LocalDateCodec
en DutyBlockCodec
, dit is nogal verwarrend, en MongoDB biedt een functionaliteit, de CodecProvider
om dit proces te vergemakkelijken.
De CodecProvider
gebruiken interface, schreef ik een 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;
}
}
Ik heb deze CodecProviders
toegevoegd naar de MongoDB-client met behulp van de CodecRegistries.fromProviders()
methode.
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");
Mijn broncode voor dit project is te vinden op https://github.com/desrepair/DutyScheduler. Ik sta open voor het beantwoorden van alle vragen die mensen hebben.