sql >> Databáze >  >> NoSQL >> MongoDB

Při kódování objektu se nepoužívá kodek MongoDB BSON

Po několika dnech výzkumu jsem přišel na řešení.

DutyBlockCodec závisí na LocalDateCodec (který jsem vytvořil) za účelem kódování/dekódování. Tato závislost není uspokojena pouhým přidáním dvou kodeků do stejného registru kodeků. Řešením je předat CodecRegistry objekt obsahující kodeky, které DutyBlockCodec závisí na (např. CodecRegistry obsahující v sobě LocalDateCodec ) do DutyBlockCodec 's konstruktor, který je uložen jako členská proměnná. Chcete-li použít LocalDateCodec ke kódování používám EncoderContext.encodeWithChildContext() metoda, předání kodeku, zapisovače a prvku ke kódování. Navíc píšu jednotlivá pole místo psaní Document jako String (jako v mém původním kódu). Tedy DutyBlock kodek nakonec vypadá takto:

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 závisí na jiném kodeku, a proto vyžaduje CodecRegistry který má být předán jeho konstruktérovi. I když věřím, že je možné vytvořit CodecRegistry pomocí LocalDateCodec , pak to předejte jako argument do DutyBlockCodec 's konstruktor, pak vytvořte další CodecRegistry obsahující oba LocalDateCodec a DutyBlockCodec , je to poněkud matoucí a MongoDB poskytuje funkci, CodecProvider k usnadnění tohoto procesu.

Pomocí CodecProvider rozhraní, napsal jsem 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;
    }
}

Přidal jsem tyto CodecProviders do klienta MongoDB pomocí CodecRegistries.fromProviders() metoda.

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");

Můj zdrojový kód pro tento projekt lze nalézt na https://github.com/desrepair/DutyScheduler Jsem otevřený zodpovězení jakýchkoli otázek, které lidé mohou mít.



  1. Jak mohu spustit skript MongoDB js pomocí Java MongoDriver

  2. "Pole vyžadovalo fazoli typu, který nebylo možné najít." error spring restful API pomocí mongodb

  3. Populace mangusty vs vnoření objektů

  4. Databáze klíčů a hodnot s klientem Java