MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Le codec MongoDB BSON n'est pas utilisé lors de l'encodage de l'objet

Après plusieurs jours de recherche, j'ai trouvé une solution.

Le DutyBlockCodec dépend du LocalDateCodec (que j'ai créé) afin d'encoder/décoder. Cette dépendance n'est pas satisfaite simplement en ajoutant les deux codecs dans le même registre de codecs. La solution est de passer un CodecRegistry objet contenant les codecs que DutyBlockCodec dépend de (par exemple, un CodecRegistry contenant en son sein le LocalDateCodec ) au DutyBlockCodec le constructeur de , qui est stocké en tant que variable membre. Pour utiliser le LocalDateCodec pour encoder, j'utilise le EncoderContext.encodeWithChildContext() méthode, en transmettant le codec, le rédacteur et l'élément à encoder. De plus, j'écris des champs individuels plutôt que d'écrire un Document sous forme de String (comme dans mon code d'origine). Ainsi le DutyBlock codec finit par ressembler à ceci :

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 dépend d'un autre codec, et nécessite donc un CodecRegistry à transmettre à son constructeur. Bien que je pense qu'il est possible de créer un CodecRegistry avec le LocalDateCodec , puis passez ceci comme argument à DutyBlockCodec du constructeur, puis créez un autre CodecRegistry contenant à la fois LocalDateCodec et DutyBlockCodec , c'est plutôt déroutant, et MongoDB fournit une fonctionnalité, le CodecProvider pour faciliter ce processus.

Utilisation du CodecProvider interface, j'ai écrit 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;
    }
}

J'ai ajouté ces CodecProviders au client MongoDB en utilisant le CodecRegistries.fromProviders() méthode.

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

Mon code source pour ce projet peut être trouvé à https://github.com/desrepair/DutySchedulerJe suis ouvert à répondre à toutes les questions que les gens pourraient avoir.