Search code examples
javaspring-bootcouchbasespring-data-couchbasecouchbase-java-api

How to handle Couchbase SDK 2 based JsonDocument format usage when migrating to Couchbase SDK 3?


When migrating from Couchbase SDK 2 to SDK 3 certain document formats seem to have been removed. Our current development which was based on Couchbase SDK 2, has extensively used the JsonDocument format (com.couchbase.client.java.document.JsonDocument).

How can this format or an alternative output be used in Couchbase SDK 3 to handle the below-indicated API change?

This is one of the sample classes that used JsonDocument in the existing system.

import com.couchbase.client.java.Bucket;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
import com.couchbase.client.java.document.JsonDocument; 
import com.couchbase.client.java.document.json.JsonObject;

public class CouchbaseConnector {

    private Bucket bucket;
    
    private CouchbaseConnector(Bucket bucket) {
        this.bucket = bucket;
    }

    public static Builder builder() {

        return new Builder();
    }

    public JsonDocument insert(String id, String jsonString) {

        JsonObject content = JsonObject.fromJson(jsonString);
        return insert(id, content);
    }

    public JsonDocument insert(String id, JsonObject jsonObject) { 

        JsonDocument document = JsonDocument.create(id, jsonObject);
        return insert(document);
    }

    public JsonDocument insert(JsonDocument document) {
        return bucket.insert(document);
    }

    public JsonDocument retrieve(String id) {
        return bucket.get(id);
    }

    public JsonDocument remove(String id) {

        try {
            return bucket.remove(id);
        } catch (Exception e) {
            return null;
        }
    }

    public boolean flush() {
        return bucket.bucketManager().flush();
    }
}

For example, to in order to handle the insertion functionality in Couchbase SDK 3, I believe can be handled as mentioned below.

public void insert(String id, String jsonString, Collection collection) {
        MutationResult upsertResult =null;
        JsonObject content = JsonObject.fromJson(jsonString);

     try{
     //Insert Document
     upsertResult = collection.upsert(id, content);
     }Catch (CasMismatchException e){
      //To Do: the caller is expected to re-do the whole "fetch-modify-update" cycle again
     }

    //Retrieve the document
    GetResult getResult = collection.get(id).contentAsObject();
     
    }

But how can I return a document format similar to JsonDocument or an alternative format without breaking the current code after the migration to Couchbase SDK 3?


Solution

  • But how can I return a document format similar to JsonDocument or an alternative format without breaking the current code after the migration to Couchbase SDK 3?

    In general, it's not possible to upgrade to SDK 3 without breaking some part of your code. However, you can write you own JsonDocument class that looks a bit like SDK 2's JsonDocument.

    In a comparison of SDK 2.x Document vs. SDK 3.x Transcoder table JsonDocument is mentioned as replaced by JsonTranscoder. Could some assistance be provided on how these details may be utilized in handling the above issue?

    In SDK 2, if you wanted to insert a JSON document into the database, you passed a JsonDocument to bucket.insert(document).

    In SDK 3, you pass any object as the content for collection.insert(id, content), and the SDK uses a transcoder to convert the object to your desired format. You control the format by specifying which transcoder to use. The default is JsonTranscoder, which uses data binding to convert the Java object to JSON.

    When retrieving a document in SDK 3, you get a GetResult instead of a Document. This GetResult has all the same information as a JsonDocument, but in a more flexible format. For example, you can get the raw content bytes of a GetResult by calling result.contentAsBytes(). You can use data binding to convert the content to any compatible Java class by calling result.contentAs(MyJavaClass.class), or even a list of such classes by calling result.contentAs(new TypeRef<List<MyJavaClass>>() {}).

    Here's my quick attempt at porting most of CouchbaseConnector to SDK 3:

    import com.couchbase.client.core.error.DocumentNotFoundException;
    import com.couchbase.client.java.Collection;
    import com.couchbase.client.java.codec.RawJsonTranscoder;
    import com.couchbase.client.java.json.JsonObject;
    import com.couchbase.client.java.kv.GetResult;
    import com.couchbase.client.java.kv.InsertOptions;
    import com.couchbase.client.java.kv.MutationResult;
    
    import static java.util.Objects.requireNonNull;
    
    public class CouchbaseConnector {
      /**
       * Associates a document ID with a JsonObject.
       */
      public static class JsonDocument {
        private final String id;
        private final JsonObject content; // nullable!
    
        public JsonDocument(String id, JsonObject content) {
          this.id = requireNonNull(id);
          this.content = content;
        }
    
        public String id() {
          return id;
        }
    
        public JsonObject content() {
          return content;
        }
      }
    
      private final Collection collection;
    
      public CouchbaseConnector(Collection collection) {
        this.collection = requireNonNull(collection);
      }
    
      public MutationResult insert(String id, String jsonString) {
        // Use RawJsonTranscoder.INSTANCE when you have a String or byte array
        // containing pre-formatted JSON:
        return collection.insert(id, jsonString,
          InsertOptions.insertOptions()
            .transcoder(RawJsonTranscoder.INSTANCE)
        );
      }
    
      public MutationResult insert(String id, JsonObject jsonObject) {
        // Use the JsonTranscoder (the default) with JsonObject,
        // and any other Java object compatible with JSON data binding:
        return collection.insert(id, jsonObject);
      }
    
      public MutationResult insert(JsonDocument document) {
        return collection.insert(document.id(), document.content());
      }
    
      public GetResult retrieve(String id) throws DocumentNotFoundException {
        return collection.get(id);
      }
    
      @Deprecated
      public JsonDocument retrieveAsJsonObject(String id) throws DocumentNotFoundException {
        GetResult result = collection.get(id);
        return new JsonDocument(id, result.contentAsObject());
      }
    
      public MutationResult remove(String id) {
        try {
          return collection.remove(id);
        } catch (DocumentNotFoundException e) {
          return null;
        }
      }
    
      @Deprecated
      public JsonDocument removeAsJsonDocument(String id) {
        MutationResult result = remove(id);
        return result == null ? null : new JsonDocument(id, null);
      }
    }