简体   繁体   中英

Upsert Document with a generic json field

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

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM