当使用MongoDB的默认POJO编解码器序列化到BSON时,如何不忽略null属性?

oyxsuwqo  于 2022-12-22  发布在  Go
关注(0)|答案(2)|浏览(155)

我有一个类包含一个可空字段:

public class User {
  @BsonId
  public ObjectId _id;
  // Nullable
  public String wechat_unionid;
  // Nullable
  public String wework_userid;
}

我使用mongodbjava驱动程序的默认POJOCodec,它将忽略null属性,但我需要它为null并存在,否则它将无法通过模式验证。
文件中:https://mongodb.github.io/mongo-java-driver/4.1/bson/pojos/
上面写着:
默认情况下,空值不会被序列化。这由FieldSerialization接口的默认实现控制。可以在ClassModelBuilder中提供的PropertyModelBuilder上设置自定义实现。
但我不知道怎么定制?
我该怎么办?还有别的办法吗?
谢谢!

z9ju0rcb

z9ju0rcb1#

我从官方的java驱动程序文档中找到了一个解决方案,它可以成功地工作。这个配置使mongo驱动程序创建字段"年龄",即使"年龄"的值为空。帮助会对你有帮助。

package com.alan.db.mongo;

import com.mongodb.MongoClientSettings;
import com.mongodb.client.*;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.codecs.pojo.*;

import java.util.List;
import java.util.function.Consumer;

import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
import static org.bson.codecs.configuration.CodecRegistries.fromRegistries;

public class InsertTest {
    public static final String CONNECTION_STRING = "mongodb://alan:alan@127.0.0.1:27017";
    static MongoClient mongoClient;
    static MongoDatabase database;
    static MongoCollection<Student> collection;

    static {
        ClassModelBuilder classModelBuilder = ClassModel.builder(Student.class);
        classModelBuilder.getProperty("age").propertySerialization(new MyPropertySerialization<>());
        PojoCodecProvider.builder().register(classModelBuilder.build());
        mongoClient = MongoClients.create(CONNECTION_STRING);
        CodecRegistry pojoCodecRegistry = fromRegistries(MongoClientSettings.getDefaultCodecRegistry(),
                fromProviders(PojoCodecProvider.builder().register(classModelBuilder.build()).automatic(true).build()));
        database = mongoClient.getDatabase("test").withCodecRegistry(pojoCodecRegistry);
        collection = database.getCollection("student", Student.class);
    }

    public static void main(String[] args) {
        InsertTest client = new InsertTest();
        client.collection.insertOne(new Student("tony", null));
        FindIterable<Student> students = client.collection.find();
        Consumer<Student> consumer = student -> System.out.println(student);
        students.forEach(consumer);
    }
}
public class Student {
    private String name;
    private Integer age;

    public Student() { }

    public Student(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public class MyPropertySerialization<T> implements PropertySerialization<T> {
    @Override
    public boolean shouldSerialize(T value) {
        return true;
    }
}
tyg4sfes

tyg4sfes2#

您可以使用 PropertyModelBuilder 类(可在 ClassModelBuilder 类中使用)控制是否将POJO类的属性序列化为 Document。为所有POJO类获取 ClassModelBuilder 的最简单方法是在POJO CodecRegistry 中声明自定义 Convention
首先,创建 NullableConvention 类:

public class NullableConvention implements Convention {
    @Override
    public void apply(ClassModelBuilder<?> cmb) {
        for(PropertyModelBuilder<?> pmb : cmb.getPropertyModelBuilders()){ //edit all properties
            pmb.propertySerialization(new PropertySerialization(){
                @Override
                public boolean shouldSerialize(Object t) {
                    return true; //always serialize object even if t == null
                }
            });
        }
    }
}

然后,将新的 * 约定 * 附加到 PojoCodecProvider 中:

List<Convention> conventions = new ArrayList<>(); // your customs conventions go here
conventions.add(new NullableConvention()); // custom convention
conventions.addAll(Conventions.DEFAULT_CONVENTIONS); // mongo's driver default conventions
CodecRegistry pojoCodecRegistry = CodecRegistries.fromProviders(PojoCodecProvider.builder().conventions(conventions).build()); //add your conventions to pojo provider

相关问题