Efter flera dagars research har jag hittat en lösning.
DutyBlockCodec
beror på LocalDateCodec
(som jag skapade) för att koda/avkoda. Detta beroende är inte tillfredsställt bara genom att lägga till de två kodekarna i samma codec-register. Lösningen är att skicka ett CodecRegistry
objekt som innehåller codecs som DutyBlockCodec
beror på (t.ex. ett CodecRegistry
som innehåller LocalDateCodec
) till DutyBlockCodec
s konstruktor, som lagras som en medlemsvariabel. För att använda LocalDateCodec
för att koda använder jag EncoderContext.encodeWithChildContext()
metod som skickar in codec, writer och element för att koda. Dessutom skriver jag enskilda fält istället för att skriva ett Document
som en String
(som i min ursprungliga kod). Alltså DutyBlock
codec ser ut så här:
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
beror på en annan codec och kräver därför ett CodecRegistry
ska skickas in på dess konstruktör. Även om jag tror att det är möjligt att skapa ett CodecRegistry
med LocalDateCodec
, skicka sedan detta som ett argument till DutyBlockCodec
s konstruktor och skapa sedan ett annat CodecRegistry
som innehåller både LocalDateCodec
och DutyBlockCodec
, detta är ganska förvirrande, och MongoDB tillhandahåller en funktionalitet, CodecProvider
för att underlätta denna process.
Använda CodecProvider
gränssnitt skrev jag 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;
}
}
Jag lade till dessa CodecProviders
till MongoDB-klienten med hjälp av CodecRegistries.fromProviders()
metod.
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 källkod för detta projekt finns på https://github.com/desrepair/DutySchedulerJag är öppen för att svara på alla frågor som folk kan ha.