From 3f0e5b22c3411d70cc6ab2bc55dab9137d0d3713 Mon Sep 17 00:00:00 2001 From: Pasin Suriyentrakorn Date: Tue, 9 Jun 2026 19:51:59 -0700 Subject: [PATCH] CBL-8389 : Fix build and static analysis issues in kt-serialization API changes * Replace var with explicit FLDict type in Document.setContent (common is compiled at Java 8) * Suppress PMD SingularField and SpotBugs URF_UNREAD_FIELD on Document.extraBackingStore (keep-alive field) * Add null check on FLValue.fromData() result in Document.setContent (NP_NULL_ON_SOME_PATH) * Move serialization tests from test/java to test/kotlin so that only the android-ktx test builds compile them : - FleeceSerializationTest.kt moved as-is - ResultTest.kt renamed to ResultSerializationTest.kt - Serialization test and TestModel extracted from CollectionTest.kt into new CollectionSerializationTest.kt --- .../java/com/couchbase/lite/Document.java | 7 +- .../java/com/couchbase/lite/CollectionTest.kt | 50 ------------- .../lite/CollectionSerializationTest.kt | 74 +++++++++++++++++++ .../lite/ResultSerializationTest.kt} | 2 +- .../fleece/FleeceSerializationTest.kt | 0 5 files changed, 80 insertions(+), 53 deletions(-) create mode 100644 common/test/kotlin/com/couchbase/lite/CollectionSerializationTest.kt rename common/test/{java/com/couchbase/lite/ResultTest.kt => kotlin/com/couchbase/lite/ResultSerializationTest.kt} (99%) rename common/test/{java => kotlin}/com/couchbase/lite/internal/fleece/FleeceSerializationTest.kt (100%) diff --git a/common/main/java/com/couchbase/lite/Document.java b/common/main/java/com/couchbase/lite/Document.java index fb8e6922f..ccbd2f825 100644 --- a/common/main/java/com/couchbase/lite/Document.java +++ b/common/main/java/com/couchbase/lite/Document.java @@ -136,6 +136,8 @@ static Document getDocumentWithRevisions(@NonNull Collection collection, @NonNul // Set by setData(FLSliceResult,boolean) to keep the Fleece backing store from being GC'd. // (This is kind of a hack, and it's only used ephemerally by Kotlin serialization.) + @SuppressFBWarnings("URF_UNREAD_FIELD") + @SuppressWarnings("PMD.SingularField") @GuardedBy("lock") @Nullable private FLSliceResult extraBackingStore; @@ -632,9 +634,10 @@ private void setC4Document(@Nullable C4Document c4doc, boolean mutable) { // for use by CollectionExtensions.kt void setContent(@NonNull FLSliceResult fleeceData, boolean mutable) { synchronized (lock) { - var data = FLValue.fromData(fleeceData).asFLDict(); + final FLValue body = FLValue.fromData(fleeceData); + if (body == null) { throw new CouchbaseLiteError("Failed parsing fleece data"); } extraBackingStore = fleeceData; - setContentLocked(data, mutable); + setContentLocked(body.asFLDict(), mutable); } } diff --git a/common/test/java/com/couchbase/lite/CollectionTest.kt b/common/test/java/com/couchbase/lite/CollectionTest.kt index c7e96c728..7bc7c80cd 100644 --- a/common/test/java/com/couchbase/lite/CollectionTest.kt +++ b/common/test/java/com/couchbase/lite/CollectionTest.kt @@ -17,8 +17,6 @@ package com.couchbase.lite import com.couchbase.lite.internal.utils.SlowTest -import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient import org.junit.Assert import org.junit.Test @@ -1215,52 +1213,4 @@ class CollectionTest : BaseDbTest() { Assert.assertEquals(scope, testDatabase.getScope(Scope.DEFAULT_NAME)) } - - //--------------------------------------------- - // Model-based (serialization) API - //--------------------------------------------- - - @Test - fun saveNewDocInCollectionFromModel() { - val id = getUniqueName("test_doc") - - // Create a new model and save it: - val model = TestModel("Nigel", 12) - testCollection.save(model, id) - Assert.assertEquals(testCollection, model.documentMeta?.collection) - Assert.assertEquals(id, model.documentMeta?.id) - - // Read it back: - Assert.assertEquals(1, testCollection.count) - val gotModel = testCollection.getDocumentAs(id)!! - Assert.assertEquals(model, gotModel) - - // Modify and save again: - gotModel.favorites = listOf("XTC", "Elvis Costello") - Assert.assertTrue(testCollection.save(gotModel)) - Assert.assertNotEquals(model.documentMeta?.revisionID, gotModel.documentMeta?.revisionID) - - // Get it as a regular Document and verify the contents: - val doc = testCollection.getDocument(id)!! - Assert.assertEquals(gotModel.documentMeta?.revisionID, doc.revisionID) - Assert.assertEquals("Nigel", doc.getString("name")) - Assert.assertEquals(12, doc.getInt("age")) - val faves = doc.getArray("favorites")!! - Assert.assertEquals(2, faves.count()) - Assert.assertEquals("XTC", faves.getString(0)) - Assert.assertEquals("Elvis Costello", faves.getString(1)) - - // Delete the model. `model` is out of date, so it will fail, but `gotModel` is OK: - Assert.assertFalse(testCollection.delete(model, ConcurrencyControl.FAIL_ON_CONFLICT)) - Assert.assertTrue(testCollection.delete(gotModel, ConcurrencyControl.FAIL_ON_CONFLICT)) - } -} - - -// Simple Model class for tests -@Serializable -data class TestModel(var name: String, - var age: Int, - var favorites: List? = null): DocumentModel { - @Transient override var documentMeta: DocumentMeta? = null } diff --git a/common/test/kotlin/com/couchbase/lite/CollectionSerializationTest.kt b/common/test/kotlin/com/couchbase/lite/CollectionSerializationTest.kt new file mode 100644 index 000000000..7d79033cf --- /dev/null +++ b/common/test/kotlin/com/couchbase/lite/CollectionSerializationTest.kt @@ -0,0 +1,74 @@ +// +// Copyright (c) 2026 Couchbase, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http:// www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package com.couchbase.lite + +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import org.junit.Assert +import org.junit.Test + + +/** Tests serialization-based Collection accessors implemented in CollectionExtensions.kt. */ +class CollectionSerializationTest : BaseDbTest() { + //--------------------------------------------- + // Model-based (serialization) API + //--------------------------------------------- + + @Test + fun saveNewDocInCollectionFromModel() { + val id = getUniqueName("test_doc") + + // Create a new model and save it: + val model = TestModel("Nigel", 12) + testCollection.save(model, id) + Assert.assertEquals(testCollection, model.documentMeta?.collection) + Assert.assertEquals(id, model.documentMeta?.id) + + // Read it back: + Assert.assertEquals(1, testCollection.count) + val gotModel = testCollection.getDocumentAs(id)!! + Assert.assertEquals(model, gotModel) + + // Modify and save again: + gotModel.favorites = listOf("XTC", "Elvis Costello") + Assert.assertTrue(testCollection.save(gotModel)) + Assert.assertNotEquals(model.documentMeta?.revisionID, gotModel.documentMeta?.revisionID) + + // Get it as a regular Document and verify the contents: + val doc = testCollection.getDocument(id)!! + Assert.assertEquals(gotModel.documentMeta?.revisionID, doc.revisionID) + Assert.assertEquals("Nigel", doc.getString("name")) + Assert.assertEquals(12, doc.getInt("age")) + val faves = doc.getArray("favorites")!! + Assert.assertEquals(2, faves.count()) + Assert.assertEquals("XTC", faves.getString(0)) + Assert.assertEquals("Elvis Costello", faves.getString(1)) + + // Delete the model. `model` is out of date, so it will fail, but `gotModel` is OK: + Assert.assertFalse(testCollection.delete(model, ConcurrencyControl.FAIL_ON_CONFLICT)) + Assert.assertTrue(testCollection.delete(gotModel, ConcurrencyControl.FAIL_ON_CONFLICT)) + } +} + + +// Simple Model class for tests +@Serializable +data class TestModel(var name: String, + var age: Int, + var favorites: List? = null): DocumentModel { + @Transient override var documentMeta: DocumentMeta? = null +} diff --git a/common/test/java/com/couchbase/lite/ResultTest.kt b/common/test/kotlin/com/couchbase/lite/ResultSerializationTest.kt similarity index 99% rename from common/test/java/com/couchbase/lite/ResultTest.kt rename to common/test/kotlin/com/couchbase/lite/ResultSerializationTest.kt index ecc1f92d3..2f5af50c3 100644 --- a/common/test/java/com/couchbase/lite/ResultTest.kt +++ b/common/test/kotlin/com/couchbase/lite/ResultSerializationTest.kt @@ -67,4 +67,4 @@ class ResultSerializationTest : BaseQueryTest() { assertFalse(iter.hasNext()) } -} \ No newline at end of file +} diff --git a/common/test/java/com/couchbase/lite/internal/fleece/FleeceSerializationTest.kt b/common/test/kotlin/com/couchbase/lite/internal/fleece/FleeceSerializationTest.kt similarity index 100% rename from common/test/java/com/couchbase/lite/internal/fleece/FleeceSerializationTest.kt rename to common/test/kotlin/com/couchbase/lite/internal/fleece/FleeceSerializationTest.kt