Reputation: 451
Using spring-data-couchbase I want to define a document with a field settings
with generic JSON. To do this, I create a class
@Document
public class SampleDoc {
@Id
@NotNull
protected String id;
@Field
private JsonNode settings;
}
When I try to persist below JSON object to this document instance
{
"someField" : "someData"
}
It is persisted in the CouchBase as
"settings": {
"_children": {
"someField": {
"type": "com.fasterxml.jackson.databind.node.TextNode",
"_value": "someData"
}
},
"type": "com.fasterxml.jackson.databind.node.ObjectNode",
"_nodeFactory": {
"_cfgBigDecimalExact": false
}
}
And when I try to get the document from database through CouchbaseRepository.findById
it returns error :
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate com.fasterxml.jackson.databind.node.ObjectNode using constructor NO_CONSTRUCTOR with arguments ] with root cause
How could I persist a generic JSON object to Couchbase and assure it to be stored as a simple JSON like :
{
//other fields
"settings" : {
"someField" : "someData"
}
//other fields
}
Thank you
Upvotes: 1
Views: 143
Reputation: 533
Edit: the converters mentioned below are now included in Spring Data Couchbase.
You can create two converters like this.
Then add them as CustomConverters by overriding the customConversions() method in AbstractCouchbaseConfiguration. The only change from the original is to add the two converters.
I opened an issue at https://github.com/spring-projects/spring-data-couchbase/issues/1650
@WritingConverter
public enum JsonNodeToMap implements Converter<JsonNode, CouchbaseDocument> {
INSTANCE;
@Override
public CouchbaseDocument convert(JsonNode source) {
if( source == null ){
return null;
}
return new CouchbaseDocument().setContent(JsonObject.fromJson(source.toString()));
}
}
@ReadingConverter
public enum MapToJsonNode implements Converter<CouchbaseDocument, JsonNode> {
INSTANCE;
static ObjectMapper mapper= new ObjectMapper();
@Override
public JsonNode convert(CouchbaseDocument source) {
if( source == null ){
return null;
}
return mapper.valueToTree(source.export());
}
}
------------------------------------------------------
public CustomConversions customConversions(CryptoManager cryptoManager, ObjectMapper objectMapper) {
List<GenericConverter> newConverters = new ArrayList();
CustomConversions customConversions = CouchbaseCustomConversions.create(configurationAdapter -> {
SimplePropertyValueConversions valueConversions = new SimplePropertyValueConversions();
valueConversions.setConverterFactory(
new CouchbasePropertyValueConverterFactory(cryptoManager, annotationToConverterMap(), objectMapper));
valueConversions.setValueConverterRegistry(new PropertyValueConverterRegistrar().buildRegistry());
valueConversions.afterPropertiesSet(); // wraps the CouchbasePropertyValueConverterFactory with CachingPVCFactory
configurationAdapter.setPropertyValueConversions(valueConversions);
configurationAdapter.registerConverters(newConverters);
configurationAdapter.registerConverter(OtherConverters.JsonNodeToMap.INSTANCE); // added
configurationAdapter.registerConverter(OtherConverters.MapToJsonNode.INSTANCE); // added
configurationAdapter.registerConverter(new OtherConverters.EnumToObject(getObjectMapper()));
configurationAdapter.registerConverterFactory(new IntegerToEnumConverterFactory(getObjectMapper()));
configurationAdapter.registerConverterFactory(new StringToEnumConverterFactory(getObjectMapper()));
configurationAdapter.registerConverterFactory(new BooleanToEnumConverterFactory(getObjectMapper()));
});
return customConversions;
}
Upvotes: 1