Nach mehreren Tagen der Recherche habe ich eine Lösung gefunden.
Der DutyBlockCodec
hängt vom LocalDateCodec
ab (die ich erstellt habe), um zu codieren/decodieren. Diese Abhängigkeit wird nicht einfach dadurch erfüllt, dass die beiden Codecs derselben Codec-Registrierung hinzugefügt werden. Die Lösung besteht darin, eine CodecRegistry
zu übergeben Objekt, das die Codecs enthält, die DutyBlockCodec
abhängig von (z.B. einer CodecRegistry
enthält darin den LocalDateCodec
) zum DutyBlockCodec
Der Konstruktor von , der als Membervariable gespeichert wird. Um den LocalDateCodec
zu verwenden Zum Codieren verwende ich den EncoderContext.encodeWithChildContext()
-Methode, wobei der Codec, der Writer und das zu codierende Element übergeben werden. Außerdem schreibe ich einzelne Felder, anstatt ein Document
zu schreiben als String
(wie in meinem ursprünglichen Code). Also der DutyBlock
Codec sieht am Ende so aus:
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
hängt von einem anderen Codec ab und erfordert daher eine CodecRegistry
an seinen Konstruktor übergeben werden. Obwohl ich glaube, dass es möglich ist, eine CodecRegistry
zu erstellen mit dem LocalDateCodec
, dann übergeben Sie dies als Argument an DutyBlockCodec
den Konstruktor von und erstellen Sie dann eine weitere CodecRegistry
die sowohl LocalDateCodec
enthalten und DutyBlockCodec
, das ist ziemlich verwirrend, und MongoDB bietet eine Funktionalität, den CodecProviders
um diesen Vorgang zu erleichtern.
Verwendung des CodecProviders
Schnittstelle habe ich einen DutyBlockCodecProvider
geschrieben
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;
}
}
Ich habe diese CodecProviders
hinzugefügt an den MongoDB-Client mithilfe von 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");
Meinen Quellcode für dieses Projekt finden Sie unter https://github.com/desrepair/DutyScheduler. Ich bin offen für die Beantwortung aller Fragen, die möglicherweise auftreten.