Skip to content

Commit 8945b42

Browse files
Merge branch 'publish'
2 parents 66da77d + 3fc0745 commit 8945b42

File tree

14 files changed

+343
-85
lines changed

14 files changed

+343
-85
lines changed

.github/workflows/close-no-response.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
pull-requests: write
1717
steps:
1818
# https://github.com/marketplace/actions/close-stale-issues
19-
- uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0
19+
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
2020
with:
2121
days-before-stale: -1 # Add the stale label manually.
2222
days-before-close: 21

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@ Notable changes to the ObjectBox Java library.
44

55
For more insights into what changed in the ObjectBox C++ core, [check the ObjectBox C changelog](https://github.com/objectbox/objectbox-c/blob/main/CHANGELOG.md).
66

7+
## 5.2.0 - 2026-02-16
8+
9+
- The [ObjectBox Gradle plugin](https://github.com/objectbox/objectbox-java-generator) requires JDK 11 and Android
10+
Gradle Plugin 8.1 or newer.
11+
- Update database libraries for Android and JVM to database version `5.1.1-pre-2026-02-16`.
12+
13+
### Sync
14+
15+
- Add simplified `Sync.client(boxStore)` helper method. Move URL and credentials options to builder, add variants that
16+
accept multiple URLs and credentials. Deprecate the existing helper methods.
17+
- Add Sync client builder option to configure Sync behavior using
18+
[SyncFlags](objectbox-java/src/main/java/io/objectbox/sync/SyncFlags.java).
19+
720
## 5.1.0 - 2026-01-26
821

922
- Add [ObjectBoxThreadPoolExecutor](objectbox-java/src/main/java/io/objectbox/ObjectBoxThreadPoolExecutor.java), a

README.md

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,16 @@ The database libraries available for the ObjectBox Java SDK support:
123123
- Windows (x64)
124124
- Android 5.0 (API level 21) or newer
125125

126-
The APIs and tools of the ObjectBox Java SDK support:
126+
The ObjectBox Java SDK supports:
127127

128128
- Java 8 or newer
129129
- Kotlin 1.7 or newer
130-
- Android Gradle Plugin 8.0 or newer
130+
131+
The [ObjectBox Gradle plugin](https://github.com/objectbox/objectbox-java-generator) supports:
132+
133+
- Gradle 7.0 or newer
134+
- Android Gradle Plugin 8.1 or newer
135+
- JDK 11 or newer
131136

132137
### Gradle setup
133138

@@ -141,7 +146,13 @@ When using a [TOML version catalog](https://docs.gradle.org/current/userguide/ve
141146

142147
[versions]
143148
# Define a variable for the version of the plugin
144-
objectbox = "5.1.0"
149+
objectbox = "5.2.0"
150+
151+
# For an Android project
152+
agp = "<AGP_VERSION>"
153+
154+
# If using Kotlin
155+
kotlin = "<KOTLIN_VERSION>"
145156

146157
# For an Android project
147158
agp = "<AGP_VERSION>"
@@ -248,7 +259,7 @@ Your project can now use ObjectBox, continue by [defining entity classes](https:
248259

249260
plugins {
250261
// Add the plugin
251-
id("io.objectbox") version "5.1.0" apply false
262+
id("io.objectbox") version "5.2.0" apply false
252263
}
253264
```
254265

@@ -281,7 +292,7 @@ pluginManagement {
281292

282293
buildscript {
283294
// Define a variable for the plugin version
284-
val objectboxVersion by extra("5.1.0")
295+
val objectboxVersion by extra("5.2.0")
285296

286297
repositories {
287298
// Add the Maven Central repository
@@ -304,7 +315,7 @@ buildscript {
304315
305316
buildscript {
306317
// Define a variable for the plugin version
307-
ext.objectboxVersion = "5.1.0"
318+
ext.objectboxVersion = "5.2.0"
308319
309320
repositories {
310321
// Add the Maven Central repository

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ plugins {
2020
buildscript {
2121
// Version of Maven artifacts
2222
// Should only be changed as part of the release process, see the release checklist in the objectbox repo
23-
val versionNumber = "5.1.0"
23+
val versionNumber = "5.2.0"
2424

2525
// Release mode should only be enabled when manually triggering a CI pipeline,
2626
// see the release checklist in the objectbox repo.

objectbox-java/src/main/java/io/objectbox/BoxStore.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,17 @@ public class BoxStore implements Closeable {
8282
* ReLinker uses this as a suffix for the extracted shared library file. If different, it will update it. Should be
8383
* unique to avoid conflicts.
8484
*/
85-
public static final String JNI_VERSION = "5.1.0-2026-01-19";
85+
public static final String JNI_VERSION = "5.1.1-2026-02-16";
8686

87-
/** The ObjectBox database version this Java library is known to work with. */
88-
private static final String VERSION = "5.1.0-2026-01-19";
87+
/**
88+
* The ObjectBox database version this Java library is known to work with.
89+
* <p>
90+
* This should be a version number followed by a date (MAJOR.MINOR.PATCH-YYYY-MM-DD).
91+
* <p>
92+
* This is used (currently only in tests) to make sure a database library has a compatible JNI API by checking the
93+
* version number matches exactly and the date is the same or newer.
94+
*/
95+
private static final String VERSION = "5.1.1-2026-02-16";
8996

9097
private static final String OBJECTBOX_PACKAGE_NAME = "objectbox";
9198
private static BoxStore defaultStore;

objectbox-java/src/main/java/io/objectbox/sync/Sync.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.objectbox.sync;
1818

19+
import java.util.Arrays;
20+
1921
import io.objectbox.BoxStore;
2022
import io.objectbox.BoxStoreBuilder;
2123
import io.objectbox.sync.server.SyncServer;
@@ -50,6 +52,23 @@ public static boolean isHybridAvailable() {
5052
return isAvailable() && isServerAvailable();
5153
}
5254

55+
/**
56+
* Starts building a {@link SyncClient} for the given {@link BoxStore}.
57+
* <p>
58+
* This does not initiate any connection attempts yet: call {@link SyncBuilder#buildAndStart()} to do so. Before,
59+
* you must configure the server URL via {@link SyncBuilder#url(String)} and add credentials via
60+
* {@link SyncBuilder#credentials(SyncCredentials)}.
61+
* <p>
62+
* By default, a Sync client automatically receives updates from the server once login succeeded. To configure this
63+
* differently, call {@link SyncBuilder#requestUpdatesMode(SyncBuilder.RequestUpdatesMode)} with the wanted mode.
64+
*
65+
* @param boxStore The {@link BoxStore} the client should use.
66+
* @return a builder to configure the Sync client
67+
*/
68+
public static SyncBuilder client(BoxStore boxStore) {
69+
return new SyncBuilder(boxStore);
70+
}
71+
5372
/**
5473
* Starts building a {@link SyncClient}. Once done, complete with {@link SyncBuilder#build() build()}.
5574
*
@@ -58,18 +77,31 @@ public static boolean isHybridAvailable() {
5877
* starting with {@code ws://} or {@code wss://} (for encrypted connections), for example
5978
* {@code ws://127.0.0.1:9999}.
6079
* @param credentials {@link SyncCredentials} to authenticate with the server.
80+
* @deprecated Use {@link #client(BoxStore)}, {@link SyncBuilder#url(String)} and
81+
* {@link SyncBuilder#credentials(SyncCredentials)} instead.
6182
*/
83+
@Deprecated
6284
public static SyncBuilder client(BoxStore boxStore, String url, SyncCredentials credentials) {
63-
return new SyncBuilder(boxStore, url, credentials);
85+
return client(boxStore)
86+
.url(url)
87+
.credentials(credentials);
6488
}
6589

6690
/**
6791
* Like {@link #client(BoxStore, String, SyncCredentials)}, but supports passing a set of authentication methods.
6892
*
6993
* @param multipleCredentials An array of {@link SyncCredentials} to be used to authenticate with the server.
94+
* @deprecated Use {@link #client(BoxStore)}, {@link SyncBuilder#url(String)} and
95+
* {@link SyncBuilder#credentials(SyncCredentials)} instead.
7096
*/
97+
@Deprecated
7198
public static SyncBuilder client(BoxStore boxStore, String url, SyncCredentials[] multipleCredentials) {
72-
return new SyncBuilder(boxStore, url, multipleCredentials);
99+
SyncBuilder builder = client(boxStore).url(url);
100+
//noinspection ConstantValue
101+
if (multipleCredentials != null) {
102+
builder.credentials(Arrays.asList(multipleCredentials));
103+
}
104+
return builder;
73105
}
74106

75107
/**

objectbox-java/src/main/java/io/objectbox/sync/SyncBuilder.java

Lines changed: 82 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,15 @@
1616

1717
package io.objectbox.sync;
1818

19+
import java.util.ArrayList;
1920
import java.util.Arrays;
20-
import java.util.Collections;
2121
import java.util.List;
2222
import java.util.Map;
2323
import java.util.TreeMap;
2424

2525
import javax.annotation.Nullable;
2626

2727
import io.objectbox.BoxStore;
28-
import io.objectbox.annotation.apihint.Internal;
2928
import io.objectbox.exception.FeatureNotAvailableException;
3029
import io.objectbox.sync.internal.Platform;
3130
import io.objectbox.sync.listener.SyncChangeListener;
@@ -36,16 +35,15 @@
3635
import io.objectbox.sync.listener.SyncTimeListener;
3736

3837
/**
39-
* A builder to create a {@link SyncClient}; the builder itself should be created via
40-
* {@link Sync#client(BoxStore, String, SyncCredentials)}.
38+
* A builder to create a {@link SyncClient}; the builder itself should be created via {@link Sync#client(BoxStore)}.
4139
*/
4240
@SuppressWarnings({"unused", "WeakerAccess"})
4341
public final class SyncBuilder {
4442

4543
final Platform platform;
4644
final BoxStore boxStore;
47-
@Nullable private String url;
48-
final List<SyncCredentials> credentials;
45+
final List<String> urls = new ArrayList<>();
46+
final List<SyncCredentials> credentials = new ArrayList<>();
4947

5048
@Nullable SyncLoginListener loginListener;
5149
@Nullable SyncCompletedListener completedListener;
@@ -56,6 +54,7 @@ public final class SyncBuilder {
5654

5755
@Nullable
5856
String[] trustedCertPaths;
57+
int flags;
5958
boolean uncommittedAcks;
6059

6160
RequestUpdatesMode requestUpdatesMode = RequestUpdatesMode.AUTO;
@@ -98,47 +97,80 @@ private static void checkSyncFeatureAvailable() {
9897
}
9998
}
10099

101-
private SyncBuilder(BoxStore boxStore, @Nullable String url, @Nullable List<SyncCredentials> credentials) {
102-
checkNotNull(boxStore, "BoxStore is required.");
103-
checkNotNull(credentials, "Sync credentials are required.");
100+
/**
101+
* Creates a builder for a {@link SyncClient}.
102+
* <p>
103+
* Don't use this directly, use the {@link Sync#client} method instead.
104+
*/
105+
SyncBuilder(BoxStore boxStore) {
106+
checkNotNull(boxStore, "boxStore");
104107
this.boxStore = boxStore;
105-
this.url = url;
106-
this.credentials = credentials;
107108
checkSyncFeatureAvailable();
108109
this.platform = Platform.findPlatform(); // Requires APIs only present in Android Sync library
109110
}
110111

111-
@Internal
112-
public SyncBuilder(BoxStore boxStore, String url, @Nullable SyncCredentials credentials) {
113-
this(boxStore, url, credentials == null ? null : Collections.singletonList(credentials));
114-
}
115-
116-
@Internal
117-
public SyncBuilder(BoxStore boxStore, String url, @Nullable SyncCredentials[] multipleCredentials) {
118-
this(boxStore, url, multipleCredentials == null ? null : Arrays.asList(multipleCredentials));
112+
/**
113+
* Adds a Sync server URL the client should connect to.
114+
* <p>
115+
* This is typically a WebSockets URL starting with {@code ws://} or {@code wss://} (for encrypted connections), for
116+
* example if the server is running on localhost {@code ws://127.0.0.1:9999}.
117+
* <p>
118+
* Can be called multiple times to add multiple URLs for high availability and load balancing (like when using an
119+
* ObjectBox Sync Server Cluster). A random URL is selected for each connection attempt.
120+
*
121+
* @param url The URL of the Sync server on which the Sync protocol is exposed.
122+
* @return this builder for chaining
123+
* @see #urls(List)
124+
*/
125+
public SyncBuilder url(String url) {
126+
checkNotNull(url, "url");
127+
this.urls.add(url);
128+
return this;
119129
}
120130

121131
/**
122-
* When using this constructor, make sure to set the server URL before starting.
132+
* Like {@link #url(String)}, but accepts a list of URLs.
133+
*
134+
* @param urls A list of URLs of Sync servers on which the Sync protocol is exposed.
135+
* @return this builder for chaining
136+
* @see #url(String)
123137
*/
124-
@Internal
125-
public SyncBuilder(BoxStore boxStore, @Nullable SyncCredentials credentials) {
126-
this(boxStore, null, credentials == null ? null : Collections.singletonList(credentials));
138+
public SyncBuilder urls(List<String> urls) {
139+
checkNotNull(urls, "urls");
140+
for (String url : urls) {
141+
url(url);
142+
}
143+
return this;
127144
}
128145

129146
/**
130-
* Allows internal code to set the Sync server URL after creating this builder.
147+
* Adds {@link SyncCredentials} to authenticate the client with the server.
148+
* <p>
149+
* The accepted credentials types depend on your Sync server configuration.
150+
*
151+
* @param credentials credentials created using a {@link SyncCredentials} factory method, for example
152+
* {@code SyncCredentials.jwtIdToken(idToken)}.
153+
* @see #credentials(List)
131154
*/
132-
@Internal
133-
SyncBuilder serverUrl(String url) {
134-
this.url = url;
155+
public SyncBuilder credentials(SyncCredentials credentials) {
156+
checkNotNull(credentials, "credentials");
157+
this.credentials.add(credentials);
135158
return this;
136159
}
137160

138-
@Internal
139-
String serverUrl() {
140-
checkNotNull(url, "Sync Server URL is null.");
141-
return url;
161+
/**
162+
* Like {@link #credentials(SyncCredentials)}, but accepts a list of credentials.
163+
*
164+
* @param credentials a list of credentials where each element is created using a {@link SyncCredentials} factory
165+
* method, for example {@code SyncCredentials.jwtIdToken(idToken)}.
166+
* @return this builder for chaining
167+
*/
168+
public SyncBuilder credentials(List<SyncCredentials> credentials) {
169+
checkNotNull(credentials, "credentials");
170+
for (SyncCredentials credential : credentials) {
171+
credentials(credential);
172+
}
173+
return this;
142174
}
143175

144176
/**
@@ -151,8 +183,8 @@ String serverUrl() {
151183
* @see SyncClient#putFilterVariable
152184
*/
153185
public SyncBuilder filterVariable(String name, String value) {
154-
checkNotNull(name, "Filter variable name is null.");
155-
checkNotNull(value, "Filter variable value is null.");
186+
checkNotNull(name, "name");
187+
checkNotNull(value, "value");
156188
filterVariables.put(name, value);
157189
return this;
158190
}
@@ -170,6 +202,16 @@ public SyncBuilder trustedCertificates(String[] paths) {
170202
return this;
171203
}
172204

205+
/**
206+
* Sets bit flags to adjust Sync behavior, like additional logging.
207+
*
208+
* @param flags One or multiple {@link SyncFlags}, combined with bitwise or.
209+
*/
210+
public SyncBuilder flags(int flags) {
211+
this.flags = flags;
212+
return this;
213+
}
214+
173215
/**
174216
* Configure automatic sync updates from the server.
175217
* If automatic sync updates are turned off, they will need to be requested using the sync client.
@@ -265,23 +307,25 @@ public SyncClient build() {
265307
if (boxStore.getSyncClient() != null) {
266308
throw new IllegalStateException("The given store is already associated with a Sync client, close it first.");
267309
}
268-
checkNotNull(url, "Sync Server URL is required.");
269310
return new SyncClientImpl(this);
270311
}
271312

272313
/**
273-
* Builds, {@link SyncClient#start() starts} and returns a Sync client.
314+
* {@link #build() Builds}, {@link SyncClient#start() starts} and returns a Sync client.
274315
*/
275316
public SyncClient buildAndStart() {
276317
SyncClient syncClient = build();
277318
syncClient.start();
278319
return syncClient;
279320
}
280321

281-
private void checkNotNull(@Nullable Object object, String message) {
282-
//noinspection ConstantConditions Non-null annotation does not enforce, so check for null.
322+
/**
323+
* Nullness annotations are only a hint in Java, so explicitly check nonnull annotated parameters
324+
* (see package-info.java for package settings).
325+
*/
326+
private void checkNotNull(@Nullable Object object, String name) {
283327
if (object == null) {
284-
throw new IllegalArgumentException(message);
328+
throw new IllegalArgumentException(name + " must not be null.");
285329
}
286330
}
287331

0 commit comments

Comments
 (0)