Mongo插入文档遇CodecConfigurationException:找不到Gson JsonObject编解码器
解决MongoDB插入时的CodecConfigurationException(找不到JsonObject的Codec)
这个错误太常见了——MongoDB Java驱动的默认编解码器只认识自己家的org.bson.Document、基本数据类型,还有标准的集合类型(比如List<Document>),完全不知道怎么处理Gson的JsonObject。从你贴的docObj内容来看,employeelist字段里存的就是Gson的JsonObject数组,这就是触发异常的直接原因。
下面给你几个实用的解决办法,按需选择:
方法1:直接把Gson JsonObject转成Mongo Document(最快捷)
既然Mongo认Document,那我们就把Gson的JsonObject转成Document就行,两者都是键值对结构,转换成本很低。
假设你现在是从jobDetails这个JsonObject里拿到employeelist,可以这么处理:
// 假设jobDetails是你拿到的Gson JsonObject JsonObject jobDetailsJson = ...; // 把JsonObject转成Mongo的Document Document jobDetailsDoc = Document.parse(jobDetailsJson.toString()); // 构建你的docObj时,用转换后的List<Document>作为employeelist的值 Document docObj = new Document() .append("files", Arrays.asList(new Document("filename", "newfile2018-04-25_03-32-01") .append("filedata", new ArrayList<>()) .append("unalloccount", 0))) .append("employeelist", jobDetailsDoc.getList("employeelist", Document.class)) .append("status", "new") .append("seq", 0) .append("_id", "jobs0"); // 现在插入就不会报错了 collection.insertOne(docObj);
方法2:自定义Codec,让Mongo驱动支持JsonObject(适合频繁转换场景)
如果你的项目里经常需要在Gson JsonObject和Mongo之间转换,可以自定义一个编解码器,注册到Mongo的配置里,这样驱动就能自动处理JsonObject了。
第一步:写自定义Codec类
import com.google.gson.JsonObject; import com.google.gson.Gson; import org.bson.Document; import org.bson.codecs.Codec; import org.bson.codecs.DecoderContext; import org.bson.codecs.EncoderContext; import org.bson.codecs.configuration.CodecRegistry; import org.bson.BsonReader; import org.bson.BsonWriter; public class JsonObjectCodec implements Codec<JsonObject> { private final Codec<Document> documentCodec; private final Gson gson = new Gson(); public JsonObjectCodec(CodecRegistry registry) { this.documentCodec = registry.get(Document.class); } @Override public JsonObject decode(BsonReader reader, DecoderContext decoderContext) { // 把Mongo的Document转成Gson JsonObject Document doc = documentCodec.decode(reader, decoderContext); return gson.fromJson(doc.toJson(), JsonObject.class); } @Override public void encode(BsonWriter writer, JsonObject value, EncoderContext encoderContext) { // 把Gson JsonObject转成Mongo的Document再编码 Document doc = Document.parse(value.toString()); documentCodec.encode(writer, doc, encoderContext); } @Override public Class<JsonObject> getEncoderClass() { return JsonObject.class; } }
第二步:注册Codec到MongoClient
import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClient; import org.bson.codecs.configuration.CodecRegistries; import org.bson.codecs.configuration.CodecRegistry; import com.mongodb.MongoClientSettings; // 注册自定义Codec CodecRegistry codecRegistry = CodecRegistries.fromRegistries( MongoClientSettings.getDefaultCodecRegistry(), CodecRegistries.fromCodecs(new JsonObjectCodec(MongoClientSettings.getDefaultCodecRegistry())) ); // 配置MongoClient MongoClientSettings settings = MongoClientSettings.builder() .codecRegistry(codecRegistry) .build(); MongoClient mongoClient = MongoClients.create(settings);
之后你再插入包含JsonObject的文档,驱动就会自动用你写的Codec处理了。
方法3:使用Mongo的POJO支持(最规范的长期方案)
如果你的项目是面向对象的,不如直接用Mongo的POJO编解码支持,这样可以完全避开JsonObject和Document的转换问题,直接操作Java对象。
第一步:定义POJO类
import java.util.List; public class Job { private List<FileDetail> files; private List<Employee> employeelist; private String status; private int seq; private String _id; // 别忘了写getter和setter,或者用Lombok简化 public List<FileDetail> getFiles() { return files; } public void setFiles(List<FileDetail> files) { this.files = files; } public List<Employee> getEmployeelist() { return employeelist; } public void setEmployeelist(List<Employee> employeelist) { this.employeelist = employeelist; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public int getSeq() { return seq; } public void setSeq(int seq) { this.seq = seq; } public String getId() { return _id; } public void setId(String id) { this._id = id; } } class FileDetail { private String filename; private List<Object> filedata; private int unalloccount; // getter和setter public String getFilename() { return filename; } public void setFilename(String filename) { this.filename = filename; } public List<Object> getFiledata() { return filedata; } public void setFiledata(List<Object> filedata) { this.filedata = filedata; } public int getUnalloccount() { return unalloccount; } public void setUnalloccount(int unalloccount) { this.unalloccount = unalloccount; } } class Employee { private String employeeid; private int datacount; // getter和setter public String getEmployeeid() { return employeeid; } public void setEmployeeid(String employeeid) { this.employeeid = employeeid; } public int getDatacount() { return datacount; } public void setDatacount(int datacount) { this.datacount = datacount; } }
第二步:注册POJO Codec并插入对象
import com.mongodb.client.MongoClients; import com.mongodb.client.MongoClient; import org.bson.codecs.configuration.CodecRegistries; import org.bson.codecs.configuration.CodecRegistry; import com.mongodb.MongoClientSettings; import org.bson.codecs.pojo.PojoCodecProvider; import com.google.gson.Gson; // 注册POJO编解码器 CodecRegistry pojoCodecRegistry = CodecRegistries.fromRegistries( MongoClientSettings.getDefaultCodecRegistry(), CodecRegistries.fromProviders(PojoCodecProvider.builder().automatic(true).build()) ); MongoClientSettings settings = MongoClientSettings.builder() .codecRegistry(pojoCodecRegistry) .build(); MongoClient mongoClient = MongoClients.create(settings); // 把jobDetails的Json转成Job对象 Job job = new Gson().fromJson(jobDetails.toString(), Job.class); // 设置其他字段比如files、status、seq、_id job.setFiles(...); // 这里可以直接传List<FileDetail> job.setStatus("new"); job.setSeq(0); job.setId("jobs0"); // 直接插入POJO对象 collection.insertOne(job);
小提醒
尽量保持项目里Mongo相关操作的数据类型一致:要么全用Mongo的Document,要么用POJO,避免混合Gson的JsonObject类型,这样能从根源减少这类编解码异常。
内容的提问来源于stack exchange,提问作者Mohan
相关产品推荐
相关产品推荐

