1. 有一个自定义的Bean对象类,代码如下:
public class TestBean extends Document{
/**
* 序列化部分不管
*/
private static final long serialVersionUID = 3610201746888594945L;
public TestBean() {
super();
}
/**
*构造函数传入3个字段值,添加到Map中
*/
public TestBean(String name, Integer sex, Date date) {
super();
this.append("name", name).append("sex", sex).append("date", date);
}
/**
*该方法用于collection的update
*/
public void setUpdate(TestBean bean){
this.append("$set", bean);
}
//以下都是获取和设置字段值
public ObjectId getId() {
return this.getObjectId("_id");
}
public void setId(ObjectId id){
this.append("_id", id);
}
public String getName() {
return this.getString("name");
}
public void setName(String name) {
this.append("name", name);
}
public Integer getSex() {
return this.getInteger("sex");
}
public void setSex(Integer sex) {
this.append("sex", sex);
}
public Date getDate() {
return this.getDate("date");
}
public void setDate(Date date) {
this.append("date", date);
}
@Override
public String toString() {
return "TestBean [id=" + getId().toString() + ", name=" + getName() + ", sex=" + getSex() + ", date=" + getDate() + "]";
}
public <TDocument> BsonDocument toBsonDocument(Class<TDocument> documentClass, CodecRegistry codecRegistry) {
// TODO Auto-generated method stub
return new BsonDocumentWrapper<TestBean>(this, codecRegistry.get(TestBean.class));
}
}
Document是Map结构的,所以字段全部存储在Map中;
最后一个方法覆写了Bson接口的定义,该方法的作用是将TestBean对象转换为BsonDocument,用到了CodecRegistry的encode方法。
2. 对应该Bean对象有一个实现了CollectibleCodec接口类的转换类:
public class TestBeanCodec implements CollectibleCodec<TestBean> {
private static final Logger LOG = LoggerFactory.getLogger(TestBeanCodec.class);
private static final String ID_FIELD_NAME = "_id";
private static final CodecRegistry DEFAULT_REGISTRY = fromProviders(asList(new ValueCodecProvider(),
new BsonValueCodecProvider(),
new DocumentCodecProvider()));
private static final BsonTypeClassMap DEFAULT_BSON_TYPE_CLASS_MAP = new BsonTypeClassMap();
private final CodecRegistry registry;
private final BsonTypeClassMap bsonTypeClassMap;
private final IdGenerator idGenerator;
private final Transformer valueTransformer;
public TestBeanCodec() {
this(DEFAULT_REGISTRY, DEFAULT_BSON_TYPE_CLASS_MAP);
}
public TestBeanCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTypeClassMap) {
this(registry, bsonTypeClassMap, null);
}
public TestBeanCodec(final CodecRegistry registry, final BsonTypeClassMap bsonTypeClassMap, final Transformer valueTransformer) {
this.registry = Assertions.notNull("registry", registry);
this.bsonTypeClassMap = Assertions.notNull("bsonTypeClassMap", bsonTypeClassMap);
this.idGenerator = Assertions.notNull("idGenerator", new ObjectIdGenerator());
this.valueTransformer = valueTransformer != null ? valueTransformer : new Transformer() {
@Override
public Object transform(final Object value) {
return value;
}
};
}
@Override
public boolean documentHasId(final TestBean document) {
return document.containsKey(ID_FIELD_NAME);
}
@Override
public BsonValue getDocumentId(final TestBean document) {
if (!documentHasId(document)) {
throw new IllegalStateException("The document does not contain an _id");
}
Object id = document.get(ID_FIELD_NAME);
if (id instanceof BsonValue) {
return (BsonValue) id;
}
BsonDocument idHoldingDocument = new BsonDocument();
BsonWriter writer = new BsonDocumentWriter(idHoldingDocument);
writer.writeStartDocument();
writer.writeName(ID_FIELD_NAME);
writeValue(writer, EncoderContext.builder().build(), id);
writer.writeEndDocument();
return idHoldingDocument.get(ID_FIELD_NAME);
}
@Override
public TestBean generateIdIfAbsentFromDocument(final TestBean document) {
if (!documentHasId(document)) {
document.put(ID_FIELD_NAME, idGenerator.generate());
}
return document;
}
@Override
public void encode(final BsonWriter writer, final TestBean document, final EncoderContext encoderContext) {
LOG.info("encoderContext.isEncodingCollectibleDocument() : "+ encoderContext.isEncodingCollectibleDocument());
writeMap(writer, document, encoderContext);
}
@Override
public TestBean decode(final BsonReader reader, final DecoderContext decoderContext) {
TestBean document = new TestBean();
reader.readStartDocument();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
String fieldName = reader.readName();
document.put(fieldName, readValue(reader, decoderContext));
}
reader.readEndDocument();
return document;
}
@Override
public Class<TestBean> getEncoderClass() {
return TestBean.class;
}
private void beforeFields(final BsonWriter bsonWriter, final EncoderContext encoderContext, final Map<String, Object> document) {
if (encoderContext.isEncodingCollectibleDocument() && document.containsKey(ID_FIELD_NAME)) {
bsonWriter.writeName(ID_FIELD_NAME);
writeValue(bsonWriter, encoderContext, document.get(ID_FIELD_NAME));
}
}
private boolean skipField(final EncoderContext encoderContext, final String key) {
return encoderContext.isEncodingCollectibleDocument() && key.equals(ID_FIELD_NAME);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private void writeValue(final BsonWriter writer, final EncoderContext encoderContext, final Object value) {
if (value == null) {
writer.writeNull();
} else if (Iterable.class.isAssignableFrom(value.getClass())) {
writeIterable(writer, (Iterable<Object>) value, encoderContext.getChildContext());
} else if (Map.class.isAssignableFrom(value.getClass())) {
writeMap(writer, (Map<String, Object>) value, encoderContext.getChildContext());
} else {
Codec codec = registry.get(value.getClass());
encoderContext.encodeWithChildContext(codec, writer, value);
}
}
private void writeMap(final BsonWriter writer, final Map<String, Object> map, final EncoderContext encoderContext) {
writer.writeStartDocument();
beforeFields(writer, encoderContext, map);
for (final Map.Entry<String, Object> entry : map.entrySet()) {
if (skipField(encoderContext, entry.getKey())) {
continue;
}
writer.writeName(entry.getKey());
writeValue(writer, encoderContext, entry.getValue());
}
writer.writeEndDocument();
}
private void writeIterable(final BsonWriter writer, final Iterable<Object> list, final EncoderContext encoderContext) {
writer.writeStartArray();
for (final Object value : list) {
writeValue(writer, encoderContext, value);
}
writer.writeEndArray();
}
private Object readValue(final BsonReader reader, final DecoderContext decoderContext) {
BsonType bsonType = reader.getCurrentBsonType();
if (bsonType == BsonType.NULL) {
reader.readNull();
return null;
} else if (bsonType == BsonType.ARRAY) {
return readList(reader, decoderContext);
} else if (bsonType == BsonType.BINARY) {
byte bsonSubType = reader.peekBinarySubType();
if (bsonSubType == BsonBinarySubType.UUID_STANDARD.getValue() || bsonSubType == BsonBinarySubType.UUID_LEGACY.getValue()) {
return registry.get(UUID.class).decode(reader, decoderContext);
}
}
return valueTransformer.transform(registry.get(bsonTypeClassMap.get(bsonType)).decode(reader, decoderContext));
}
private List<Object> readList(final BsonReader reader, final DecoderContext decoderContext) {
reader.readStartArray();
List<Object> list = new ArrayList<Object>();
while (reader.readBsonType() != BsonType.END_OF_DOCUMENT) {
list.add(readValue(reader, decoderContext));
}
reader.readEndArray();
return list;
}
}
该部分内容全部来自类DocumentCodec,将其中的Document类替换为自己的定义的Bean对象类;
该类主要实现了Codec接口定义的3个方法,分别是encode将TestBean转换为Bson,getEncoderClass获取到对象的Class类,decode将Bson转换为TestBean。
注意导入包时,要导入静态的aslist方法和fromProviders方法
import static java.util.Arrays.asList;
import static org.bson.codecs.configuration.CodecRegistries.fromProviders;
3. CURD测试:
public class DriverTest {
static{
PropertyConfigurator.configure(System.getProperty("user.dir")+ "/log4j.Properties");
}
private static final Logger LOG = LoggerFactory.getLogger(DriverTest.class);
public void startTest(){
CodecRegistry registry = CodecRegistries.fromCodecs(new TestBeanCodec());
MongoClient client = new MongoClient();
MongoDatabase database = client.getDatabase("testDb");
MongoCollection<TestBean> collection = database.withCodecRegistry(registry).getCollection("TestBeanCollec", TestBean.class);
TestBean bean = new TestBean("www",01,new Date());
//增
collection.insertOne(bean);
//查
Block<TestBean> block = new Block<TestBean>() {
public void apply(TestBean t) {
// TODO Auto-generated method stub
LOG.info(t.toString());
}
};
collection.find(bean).forEach(block);
//改
bean = new TestBean();
bean.setName("www");
TestBean newBean = new TestBean("yyy", 02, new Date());
TestBean update = new TestBean();
update.setUpdate(newBean);
collection.updateMany(bean, update);
//删
bean = new TestBean();
// bean.setId(new ObjectId("5630e02c00e65f13894071f6"));
bean.setName("www");
collection.deleteMany(bean);
client.close();
}
public static void main(String[] args) {
DriverTest test = new DriverTest();
test.startTest();
}
}
总结:这样的Bean对象还是有点繁琐,而且每一个实现CollectibleCodec接口的代码都重复而且很多,考虑到之前直接实现Codec接口的方式,可以对Bean对象创建的字段进行插入、查找、删除,但是进行更新时因为第二个参数Bson filter要传入一个类似——”$set”这样的表示如何更新数据的修饰符,而在Codec接口的实现中并不知道如何处理,这是一个以后可以继续修改完善的方向。