Skip to content

Commit d083bd3

Browse files
Merge branch 'publish'
2 parents 31bba7e + 8c1b9c3 commit d083bd3

File tree

10 files changed

+257
-12
lines changed

10 files changed

+257
-12
lines changed

CHANGELOG.md

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

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

7+
## 5.4.0 - 2026-03-24
8+
9+
- Update Android and JVM libraries to database version `5.3.0-2026-03-23`
10+
- Admin: Status tab "Count and Sizes" and "System and Info" improved
11+
12+
### Sync
13+
14+
- Conflict resolution via the new annotations `@SyncClock` and `@SyncPrecedence` (allows last win with custom conflict
15+
resolution)
16+
- Fix bad Sync client state after multiple full sync messages were interrupted
17+
- Fix adding indexes to Sync types
18+
719
## 5.3.0 - 2026-03-10
820

921
- Gradle plugin: to apply the plugin, it is no longer necessary to add a manual mapping of the plugin ID in your

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ agp = "AGP_VERSION"
151151
kotlin = "KOTLIN_VERSION"
152152

153153
# Define a variable for the version of the ObjectBox plugin
154-
objectbox = "5.3.0"
154+
objectbox = "5.4.0"
155155

156156
[plugins]
157157
# For an Android project, using Android Gradle Plugin 9.0 or newer
@@ -251,7 +251,7 @@ Your project can now use ObjectBox, continue by [defining entity classes](https:
251251

252252
plugins {
253253
// Add the ObjectBox plugin
254-
id("io.objectbox") version "5.3.0" apply false
254+
id("io.objectbox") version "5.4.0" apply false
255255
}
256256
```
257257

@@ -283,7 +283,7 @@ dependencyResolutionManagement {
283283

284284
buildscript {
285285
// Define a variable for the ObjectBox plugin version
286-
val objectboxVersion by extra("5.3.0")
286+
val objectboxVersion by extra("5.4.0")
287287

288288
repositories {
289289
// Add Maven Central to the plugin repositories
@@ -313,7 +313,7 @@ allprojects {
313313
314314
buildscript {
315315
// Define a variable for the ObjectBox plugin version
316-
ext.objectboxVersion = "5.3.0"
316+
ext.objectboxVersion = "5.4.0"
317317
318318
repositories {
319319
// Add Maven Central to the plugin repositories

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.3.0"
23+
val versionNumber = "5.4.0"
2424

2525
// Release mode should only be enabled when manually triggering a CI pipeline,
2626
// see the release checklist in the objectbox repo.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright © 2026 ObjectBox Ltd. <https://objectbox.io>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.objectbox.annotation;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Marks a {@code long} (64-bit integer) field of a {@link Sync}-enabled {@link Entity} class as the sync clock, a
26+
* "hybrid logical clock" to resolve Sync conflicts.
27+
* <p>
28+
* These clock values allow "last write wins" conflict resolution.
29+
* <p>
30+
* There can be only one sync clock per sync entity type; which is also recommended for basic conflict resolution.
31+
* <p>
32+
* For new objects, initialize the property value to {@code 0} to reserve "a slot" in the object data. ObjectBox Sync
33+
* will update this property automatically on put operations.
34+
* <p>
35+
* As a hybrid clock, it combines a wall clock with a logical counter to compensate for some clock skew effects.
36+
*/
37+
@Retention(RetentionPolicy.CLASS)
38+
@Target(ElementType.FIELD)
39+
public @interface SyncClock {
40+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright © 2026 ObjectBox Ltd. <https://objectbox.io>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.objectbox.annotation;
18+
19+
import java.lang.annotation.ElementType;
20+
import java.lang.annotation.Retention;
21+
import java.lang.annotation.RetentionPolicy;
22+
import java.lang.annotation.Target;
23+
24+
/**
25+
* Marks a {@code long} (64-bit integer) field of a {@link Sync}-enabled {@link Entity} class as the "sync precedence"
26+
* to customize Sync conflict resolution.
27+
* <p>
28+
* Developer-assigned precedence values are then used to resolve conflicts via "higher precedence wins". Defining and
29+
* assigning precedence values are completely in the hands of the developer (the ObjectBox user).
30+
* <p>
31+
* There can be only one sync precedence per sync entity type.
32+
* <p>
33+
* Typically, it is combined with a {@link SyncClock}, with the latter being the tie-breaker for equal precedence
34+
* values.
35+
*/
36+
@Retention(RetentionPolicy.CLASS)
37+
@Target(ElementType.FIELD)
38+
public @interface SyncPrecedence {
39+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ 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.2.0-2026-03-10";
85+
public static final String JNI_VERSION = "5.3.0-2026-03-23";
8686

8787
/**
8888
* The ObjectBox database version this Java library is known to work with.
@@ -92,7 +92,7 @@ public class BoxStore implements Closeable {
9292
* This is used (currently only in tests) to make sure a database library has a compatible JNI API by checking the
9393
* version number matches exactly and the date is the same or newer.
9494
*/
95-
private static final String VERSION = "5.2.0-2026-03-10";
95+
private static final String VERSION = "5.3.0-2026-03-23";
9696

9797
private static final String OBJECTBOX_PACKAGE_NAME = "objectbox";
9898
private static BoxStore defaultStore;

objectbox-java/src/main/java/io/objectbox/config/FlatStoreOptions.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 ObjectBox Ltd.
2+
* Copyright 2026 ObjectBox Ltd. <https://objectbox.io>
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -180,6 +180,11 @@ public final class FlatStoreOptions extends Table {
180180
* Flags to change the default behavior for restoring backups, e.g. what should happen to existing data.
181181
*/
182182
public long backupRestoreFlags() { int o = __offset(38); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
183+
/**
184+
* Options for write-ahead logging (WAL)
185+
*/
186+
public WalOptions walOptions() { return walOptions(new WalOptions()); }
187+
public WalOptions walOptions(WalOptions obj) { int o = __offset(40); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
183188

184189
public static int createFlatStoreOptions(FlatBufferBuilder builder,
185190
int directoryPathOffset,
@@ -199,11 +204,13 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
199204
long maxDataSizeInKbyte,
200205
int validateOnOpenKv,
201206
int backupFileOffset,
202-
long backupRestoreFlags) {
203-
builder.startTable(18);
207+
long backupRestoreFlags,
208+
int walOptionsOffset) {
209+
builder.startTable(19);
204210
FlatStoreOptions.addMaxDataSizeInKbyte(builder, maxDataSizeInKbyte);
205211
FlatStoreOptions.addValidateOnOpenPageLimit(builder, validateOnOpenPageLimit);
206212
FlatStoreOptions.addMaxDbSizeInKbyte(builder, maxDbSizeInKbyte);
213+
FlatStoreOptions.addWalOptions(builder, walOptionsOffset);
207214
FlatStoreOptions.addBackupRestoreFlags(builder, backupRestoreFlags);
208215
FlatStoreOptions.addBackupFile(builder, backupFileOffset);
209216
FlatStoreOptions.addDebugFlags(builder, debugFlags);
@@ -222,7 +229,7 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
222229
return FlatStoreOptions.endFlatStoreOptions(builder);
223230
}
224231

225-
public static void startFlatStoreOptions(FlatBufferBuilder builder) { builder.startTable(18); }
232+
public static void startFlatStoreOptions(FlatBufferBuilder builder) { builder.startTable(19); }
226233
public static void addDirectoryPath(FlatBufferBuilder builder, int directoryPathOffset) { builder.addOffset(0, directoryPathOffset, 0); }
227234
public static void addModelBytes(FlatBufferBuilder builder, int modelBytesOffset) { builder.addOffset(1, modelBytesOffset, 0); }
228235
public static int createModelBytesVector(FlatBufferBuilder builder, byte[] data) { return builder.createByteVector(data); }
@@ -244,6 +251,7 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
244251
public static void addValidateOnOpenKv(FlatBufferBuilder builder, int validateOnOpenKv) { builder.addShort(15, (short) validateOnOpenKv, (short) 0); }
245252
public static void addBackupFile(FlatBufferBuilder builder, int backupFileOffset) { builder.addOffset(16, backupFileOffset, 0); }
246253
public static void addBackupRestoreFlags(FlatBufferBuilder builder, long backupRestoreFlags) { builder.addInt(17, (int) backupRestoreFlags, (int) 0L); }
254+
public static void addWalOptions(FlatBufferBuilder builder, int walOptionsOffset) { builder.addOffset(18, walOptionsOffset, 0); }
247255
public static int endFlatStoreOptions(FlatBufferBuilder builder) {
248256
int o = builder.endTable();
249257
return o;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright © 2026 ObjectBox Ltd. <https://objectbox.io>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// automatically generated by the FlatBuffers compiler, do not modify
18+
19+
package io.objectbox.config;
20+
21+
/**
22+
* WAL flags control how the store handles WAL files.
23+
*/
24+
@SuppressWarnings("unused")
25+
public final class WalFlags {
26+
private WalFlags() { }
27+
/**
28+
* Enable WAL
29+
*/
30+
public static final int EnableWal = 1;
31+
/**
32+
* Does not wait for the disk to acknowledge
33+
*/
34+
public static final int NoFileSync = 2;
35+
}
36+
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright © 2026 ObjectBox Ltd. <https://objectbox.io>
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
// automatically generated by the FlatBuffers compiler, do not modify
18+
19+
package io.objectbox.config;
20+
21+
import java.nio.ByteBuffer;
22+
import java.nio.ByteOrder;
23+
24+
import io.objectbox.flatbuffers.BaseVector;
25+
import io.objectbox.flatbuffers.Constants;
26+
import io.objectbox.flatbuffers.FlatBufferBuilder;
27+
import io.objectbox.flatbuffers.Table;
28+
29+
/**
30+
* Options to enable and configure WAL.
31+
*/
32+
@SuppressWarnings("unused")
33+
public final class WalOptions extends Table {
34+
public static void ValidateVersion() { Constants.FLATBUFFERS_23_5_26(); }
35+
public static WalOptions getRootAsWalOptions(ByteBuffer _bb) { return getRootAsWalOptions(_bb, new WalOptions()); }
36+
public static WalOptions getRootAsWalOptions(ByteBuffer _bb, WalOptions obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
37+
public void __init(int _i, ByteBuffer _bb) { __reset(_i, _bb); }
38+
public WalOptions __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
39+
40+
/**
41+
* Flags to enable and change default WAL behavior, e.g. no sync to disk option.
42+
*/
43+
public long walFlags() { int o = __offset(4); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
44+
/**
45+
* The WAL file gets consolidated when it reached this size limit when opening the database.
46+
* This setting is meant for applications that prefer to consolidate on startup,
47+
* which may avoid consolidations on commits while the application is running.
48+
* The default is 4096 (4 MB).
49+
*/
50+
public long maxWalFileSizeOnOpenInKbyte() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
51+
/**
52+
* The WAL file gets consolidated when it reaches this size limit after a commit.
53+
* As consolidation takes some time, it is a trade-off between accumulating enough data
54+
* and the time the consolidation takes (longer with more data).
55+
* The default is 16384 (16 MB).
56+
*/
57+
public long maxWalFileSizeInKbyte() { int o = __offset(8); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
58+
59+
public static int createWalOptions(FlatBufferBuilder builder,
60+
long walFlags,
61+
long maxWalFileSizeOnOpenInKbyte,
62+
long maxWalFileSizeInKbyte) {
63+
builder.startTable(3);
64+
WalOptions.addMaxWalFileSizeInKbyte(builder, maxWalFileSizeInKbyte);
65+
WalOptions.addMaxWalFileSizeOnOpenInKbyte(builder, maxWalFileSizeOnOpenInKbyte);
66+
WalOptions.addWalFlags(builder, walFlags);
67+
return WalOptions.endWalOptions(builder);
68+
}
69+
70+
public static void startWalOptions(FlatBufferBuilder builder) { builder.startTable(3); }
71+
public static void addWalFlags(FlatBufferBuilder builder, long walFlags) { builder.addInt(0, (int) walFlags, (int) 0L); }
72+
public static void addMaxWalFileSizeOnOpenInKbyte(FlatBufferBuilder builder, long maxWalFileSizeOnOpenInKbyte) { builder.addLong(1, maxWalFileSizeOnOpenInKbyte, 0L); }
73+
public static void addMaxWalFileSizeInKbyte(FlatBufferBuilder builder, long maxWalFileSizeInKbyte) { builder.addLong(2, maxWalFileSizeInKbyte, 0L); }
74+
public static int endWalOptions(FlatBufferBuilder builder) {
75+
int o = builder.endTable();
76+
return o;
77+
}
78+
79+
public static final class Vector extends BaseVector {
80+
public Vector __assign(int _vector, int _element_size, ByteBuffer _bb) { __reset(_vector, _element_size, _bb); return this; }
81+
82+
public WalOptions get(int j) { return get(new WalOptions(), j); }
83+
public WalOptions get(WalOptions obj, int j) { return obj.__assign(__indirect(__element(j), bb), bb); }
84+
}
85+
}
86+

objectbox-java/src/main/java/io/objectbox/model/PropertyFlags.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 ObjectBox Ltd.
2+
* Copyright 2026 ObjectBox Ltd. <https://objectbox.io>
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -103,5 +103,29 @@ private PropertyFlags() { }
103103
* However, the deletion process can be triggered by an API call.
104104
*/
105105
public static final int EXPIRATION_TIME = 65536;
106+
/**
107+
* Marks a Long (64-bit integer) property as a the sync clock, a "hybrid logical clock" to resolve Sync conflicts.
108+
* These clock values allow "last write wins" conflict resolution.
109+
* There can be only one sync clock per sync entity type; which is also recommended for basic conflict resolution.
110+
* For new objects, initialize a property value to 0 to reserve "a slot" in the object data.
111+
* ObjectBox Sync will update this property automatically on put operations.
112+
* As a hybrid clock, it combines a wall clock with a logical counter to compensate for some clock skew effects.
113+
*/
114+
public static final int SYNC_CLOCK = 131072;
115+
/**
116+
* Marks a Long (64-bit integer) property as a the "sync precedence" to customize Sync conflict resolution.
117+
* Developer-assigned precedence values are then used to resolve conflicts via "higher precedence wins".
118+
* Defining and assigning precedence values are completely in the hands of the developer (the ObjectBox user).
119+
* There can be only one sync precedence per sync entity type.
120+
* Typically, it is combined with a sync clock, with the latter being the tie-breaker for equal precedence values.
121+
* This can be used to model some business logic use cases, for example:
122+
* - Setting an object a special state, e.g. a final/closed state, which may not be overwritten by a lesser state
123+
* - Multiple workflow states that occur linearly (i.e. using an increasing precedence value)
124+
* - Role based, e.g. only admins set or increment the precedence..
125+
* - “Checkpoint timestamps:” e.g. when some changes are “checked” as in approved/applied,
126+
* the precedence is updated to the current timestamp.
127+
* “Non-checked” or previously checkpointed changes are disregarded.
128+
*/
129+
public static final int SYNC_PRECEDENCE = 262144;
106130
}
107131

0 commit comments

Comments
 (0)