Can IndexConfiguration be made public?

IndexConfiguration is package-private in Java and Kotlin doesn’t play nicely with such visibility. The public Database API createIndex() uses the type in its parameters. The type is inherited by two public classes, FullTextIndexConfiguration and ValueIndexConfiguration, acting as their unifying type. IndexConfiguration's super type AbstractIndex is also itself public. Is there a reason for hiding IndexConfiguration's visibility?

For my use case, I’m creating a wrapper API in Kotlin and can’t declare the IndexConfiguration type unless its public.

Hey @jeff.lockhart : Is there a reason for making it public? Is there something, specific, that you want to do that you cannot do now?

The class is not public because it doesn’t contain anything that is part of the public API, and might provide access to things whose implementation will change. Unless there is a good reason to make it public, I’d rather not.


Hi, @blake.meike. Yes, allow me to elaborate. Without the type being public, I’m unable to declare it in my wrapper code. I’m working on a Kotlin Multiplatform API which wraps the underlying Kotlin/Java and Objective-C SDKs such that they can be used in a pure Kotlin KMM module. My wrapper API has a 1:1 representation of all types in the Couchbase Lite public API. This includes IndexConfiguration because it’s part of Database's public API as a parameter to createIndex().

I need to declare the IndexConfiguration type in order for my wrapper API to store an underlying IndexConfiguration value in order to pass to the underlying Database.createIndex() API. My wrapper IndexConfiguration type serves as the unifying super type to both FullTextIndexConfiguration and ValueIndexConfiguration, the same as it does in the wrapped Couchbase Lite API.

Currently I have to use the nearest accessible public super type to declare as the type in my wrapper API (at least this is AbstractIndex instead of Object). Then I have to check the actual type of the AbstractIndex value at runtime and cast it to either FullTextIndexConfiguration or ValueIndexConfiguration in order to pass to the underlying Database.createIndex() API as the necessary IndexConfiguration type.

Ideally, I should be able to declare the IndexConfiguration type directly in my code. I have no need to call any of the restricted constructors or methods, only the class itself needs to be made public. It makes sense it should be a public type, as it’s part of Database's public API.

It looks a bit odd too in the documentation as is. The method shows the parameter as type com.couchbase.lite.IndexConfiguration config, with no link to the type to figure out how to create such a value to pass to the API.

Additionally FullTextIndexConfiguration and ValueIndexConfiguration both indicate they extend AbstractIndex as their nearest public super type, with no indication they are actually both IndexConfigurations.

Alternatively, the Database.createIndex() API could take an AbstractIndex parameter instead, combining the two overloaded createIndex() methods which take either an Index or IndexConfiguration. This may or may not be preferable for this API.

I’d expect IndexConfiguration to behave similar to Index, which is the unifying super type of ValueIndex and FullTextIndex, which differentiates them from the *IndexConfiguration types that are also AbstractIndex subclasses. Index is a public class with no public constructors, properties, or methods.

Also of note, this isn’t an issue with wrapping the Objective-C API, as CBLIndexConfiguration is a public type.

Ok. Yeah, that’s plausible.

I’m going to ask a couple more philosophical questions, now:

  1. Why wrap the entire CBL platform? There are places that definitely need wrapping but I haven’t seen the need to wrap it all. What is the goal here.
  2. If you can provide evidence for the above, we are prepared to do the work… or to work with you to do it. We intend to support fully idiomatic Kotlin. What, specifically, can we do to make this platform better?

My goal is more than supporting idiomatic Kotlin on the JVM, but to be able to develop with CBL in a pure Kotlin KMM shared module, such that the code can be compiled to both Android/JVM and iOS/Native. The reason for wrapping the API is so that the compiler can utilize either the underlying Java or Objective-C SDK, depending on the compilation target. The Kotlin API is mostly replicated from the Java API, with only a few minor differences (like property accessors instead of getters/setters in some cases). I’m also including the KTX extension functions in the API as well.

The code utilizes the Kotlin expect/actual mechanism to create platform-specific wrapper implementations around the CBL SDKs. In some cases for the Java API this can be achieved with a simple typealias, if the underlying code matches the Kotlin API 1:1. But in other cases (like if there are static functions that need to become companion object functions or other KMM nuances) then the Java code must be wrapped similar to the ObjC. The ObjC wrapper also converts types to align properly with the underlying SDK.

My goal with the KMM wrapper API is to mirror as much of CBL’s original API as possible. There are a handful of API methods I haven’t been able to implement for one reason or another because there is no pure Kotlin unifying API to utilize, mostly I/O and Executor related functions. I mentioned some of these here a while back.

I’ve achieved good success having done this originally for v2.8.6. I’m now working on updating the API to v3.0.0. I’d like to look at open sourcing my code once it’s ready. It’d be great to partner more closely with you in this effort.

That’s pretty interesting. I have created CBL-3272 to track the issue. It is a (small) change in our API, so the proposal will have to survive API review.

1 Like

Another note on the IndexConfiguration class, comparing language SDK APIs, I noticed that Swift and ObjC both have IndexConfiguration.expressions as a public accessor, where it’s package-private in Java. Can this be made public along with IndexConfiguration as a public class? This will make implementing these extensions in my Kotlin Multiplatform bindings easier.

Just verified: that method is part of the public API. Not even going to open a ticket for this one. It will be in 3.1 in a few minutes.

btw… CBL-3272 is closed, right? You can see IndexConfiguration in 3.1?

I haven’t seen a 3.1 release yet. Is that still pending?

Oh! Yes! Very much pending. I cannot speak on the subject of releases but I can guarantee that 3.1 will not be released by the end of this summer.

I presumed that you were following the master branch and recent code. I have my doubts about these changes making it into a 3.0 point release.

I suggest you do look at recent code. There are some very big change coming, that may have a significant affect on your plans.

Oh, that makes sense. You just meant the recent changes on the master branch. I have been looking at the code there, but ran into issues building and hadn’t spent the time figuring out what’s needed to get it working. I just got it building today.

My code is mostly impacted by changes to the public API. What’s the best way to track upcoming changes to the API in 3.1? I’ve mostly been looking at source code diffs between releases. Looks like I can compare master with the release/android/3.0 branches of the ce and common repositories.

How do you know which core commit was used for a release? I don’t see a similarly numbered release branch in the repo and the root repo doesn’t have release branches or tags. Or really, how do you determine which core version is compatible with any given SDK commit? For example, I discovered this commit yesterday breaks the API currently on master.

When are the submodule commits updated in the root repo? Is there any significance to the current state of those commits vs master HEAD of each submodule repo (I’m assuming this is the most recent semi-stable code)?

What’s the preferred way to build the required native binaries? I followed these instructions for each ABI. But I’m assuming this should be more automated. This seems to state it should be automatic for Android builds, but I was getting build errors about missing .so files.

Even after putting the native binaries in the commom/lite-core/android/{ABI}/lib location, I also had to put the core C and fleece headers in commom/lite-core/android/{ABI}/include. Seems like something’s not working as expected where this needed to be done manually.

How do you know which core commit was used for a release?

Before 3.1, you have to look at the submodule commit for LitecCore in the rood directory. As of 3.1, though, both JVM and Android use prebuilt Cores, whose version is identified in the top level file core_version.txt

When are the submodule commits updated in the root repo? Is there any significance to the current state of those commits vs master HEAD of each submodule repo (I’m assuming this is the most recent semi-stable code)?

I try to keep core up to date, but id do not update it while I am in the middle of some large project. I want to be sure that the bugs I see are mine.

What’s the preferred way to build the required native binaries?

In 3.0, Android used the NDK to build its binaries. There is a script that builds for the JVM, and it probably still works. This is going to get harder for CE users, now that we are using pre-built Core. Getting a community script/readme together to make it easier is definitely on my list of things to do.

I put together a shell script to build the core binaries. Here’s a gist in case it’s helpful for anyone.