MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Il codec MongoDB BSON non viene utilizzato durante la codifica dell'oggetto

Dopo diversi giorni di ricerca, ho trovato una soluzione.

Il DutyBlockCodec dipende dal LocalDateCodec (che ho creato) per codificare/decodificare. Questa dipendenza non viene soddisfatta semplicemente aggiungendo i due codec nello stesso registro dei codec. La soluzione è passare un CodecRegistry oggetto contenente i codec che DutyBlockCodec dipende da (ad es. un CodecRegistry contenente al suo interno il LocalDateCodec ) al DutyBlockCodec 's, che viene archiviato come variabile membro. Per utilizzare il LocalDateCodec per codificare, utilizzo EncoderContext.encodeWithChildContext() metodo, passando il codec, lo scrittore e l'elemento da codificare. Inoltre, scrivo singoli campi invece di scrivere un Document come String (come nel mio codice originale). Quindi il DutyBlock il codec finisce per assomigliare a questo:

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 dipende da un altro codec, quindi richiede un CodecRegistry da trasmettere al suo costruttore. Anche se credo sia possibile creare un CodecRegistry con il LocalDateCodec , quindi passalo come argomento a DutyBlockCodec 's, quindi crea un altro CodecRegistry contenente entrambi LocalDateCodec e DutyBlockCodec , questo è piuttosto confuso e MongoDB fornisce una funzionalità, il CodecProvider per facilitare questo processo.

Utilizzando il CodecProvider interfaccia, ho scritto un 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;
    }
}

Ho aggiunto questi CodecProviders al client MongoDB utilizzando CodecRegistries.fromProviders() metodo.

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

Il mio codice sorgente per questo progetto può essere trovato su https://github.com/desrepair/DutyScheduler Sono aperto a rispondere a tutte le domande che le persone potrebbero avere.