如何在Spring Data Couchbase中持久化通用JSON字段并正常读写?
你遇到的这个问题其实很常见——Spring Data Couchbase默认的序列化机制会把JsonNode的内部类结构(比如那些_children、type属性)直接存进Couchbase,而不是它所代表的简洁JSON内容。查询时抛出的异常则是因为ObjectNode没有公共无参构造函数,默认的反序列化器无法实例化它。
下面给你两种靠谱的解决办法,按需选择:
方法一:改用Map<String, Object>(最简单直接)
如果你的业务场景不需要严格使用JsonNode,换成Map<String, Object>是最省心的方案,Spring Data Couchbase会自动把它序列化为简洁的JSON对象,反序列化也完全没问题:
@Document public class SampleDoc { @Id @NotNull protected String id; @Field private Map<String, Object> settings; }
这样存储后,settings字段就会是你想要的简洁格式:
"settings": { "someField": "someData" }
方法二:自定义JsonNode的序列化/反序列化器(保留JsonNode类型)
如果必须使用JsonNode,那我们需要为它编写自定义的序列化和反序列化逻辑,让Spring Data Couchbase正确处理它的JSON内容。
步骤1:编写自定义转换器
创建一个实现Converter<JsonNode, Object>的序列化器,以及Converter<Object, JsonNode>的反序列化器:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.convert.converter.Converter; import org.springframework.data.convert.ReadingConverter; import org.springframework.data.convert.WritingConverter; @WritingConverter public class JsonNodeToObjectConverter implements Converter<JsonNode, Object> { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public Object convert(JsonNode source) { return objectMapper.convertValue(source, Object.class); } } @ReadingConverter public class ObjectToJsonNodeConverter implements Converter<Object, JsonNode> { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public JsonNode convert(Object source) { return objectMapper.valueToTree(source); } }
步骤2:注册转换器到Couchbase配置
接下来需要把这两个转换器注册到Spring Data Couchbase的配置中,让它使用我们的自定义逻辑:
import org.springframework.context.annotation.Configuration; import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration; import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions; import java.util.Arrays; @Configuration public class CouchbaseConfig extends AbstractCouchbaseConfiguration { // 这里填写你的Couchbase连接信息 @Override public String getConnectionString() { return "couchbase://localhost"; } @Override public String getUserName() { return "admin"; } @Override public String getPassword() { return "password"; } @Override public String getBucketName() { return "your-bucket"; } // 注册自定义转换器 @Override public CouchbaseCustomConversions customConversions() { return new CouchbaseCustomConversions(Arrays.asList( new JsonNodeToObjectConverter(), new ObjectToJsonNodeConverter() )); } }
这样配置后,Spring Data Couchbase就会正确地把JsonNode序列化为简洁的JSON对象,查询时也能正常反序列化为JsonNode实例了。
另外还有个小技巧:如果你用的是较新版本的Spring Data Couchbase(比如3.x+),也可以尝试使用@Field配合Jackson的@JsonSerialize和@JsonDeserialize注解直接指定JsonNode的序列化器,但上面的转换器方法兼容性更好,覆盖更多场景。
内容的提问来源于stack exchange,提问作者serkanz

