# ObjectBox Java Database (Kotlin, Android)
-[ObjectBox](https://objectbox.io/) is a superfast object-oriented Java database with strong relation support and easy-to-use native language APIs.
-ObjectBox is embedded into your Android, Linux, macOS, or Windows app.
+Java database - simple but powerful, frugal but fast. Embedded into your Android, Linux, macOS, iOS, or Windows app, store and manage data easily, enjoy ludicrous speed, build ecoconciously ๐
-**Latest version: `3.3.1` (2022/09/05, [Release Notes](https://docs.objectbox.io/#objectbox-changelog))**
-
-โค **Your opinion matters to us!** Please fill in this 2-minute [Anonymous Feedback Form](https://forms.gle/bdktGBUmL4m48ruj7).
-
-Demo code using ObjectBox:
-
-```kotlin
-// Kotlin
-val playlist = Playlist("My Favorites")
-playlist.songs.add(Song("Lalala"))
-playlist.songs.add(Song("Lololo"))
-box.put(playlist)
-```
+### Demo code
```java
// Java
@@ -34,35 +33,48 @@ playlist.songs.add(new Song("Lalala"));
playlist.songs.add(new Song("Lololo"));
box.put(playlist);
```
+--> [More details in the docs](https://docs.objectbox.io/)
-๐งพ **Want details?** [Read the docs](https://docs.objectbox.io/)
+```kotlin
+// Kotlin
+val playlist = Playlist("My Favorites")
+playlist.songs.add(Song("Lalala"))
+playlist.songs.add(Song("Lololo"))
+box.put(playlist)
+```
## Table of Contents
-- [Why use ObjectBox](#why-use-objectbox)
+- [Why use ObjectBox](#why-use-objectbox-for-java-data-management--kotlin-data-management)
- [Features](#features)
-- [Gradle setup](#gradle-setup)
-- [First steps](#first-steps)
+- [How to get started](#how-to-get-started)
+ - [Gradle setup](#gradle-setup)
+ - [First steps](#first-steps)
- [Already using ObjectBox?](#already-using-objectbox)
- [Other languages/bindings](#other-languagesbindings)
- [License](#license)
----
-## Why use ObjectBox
+## Why use ObjectBox for Java data management / Kotlin data management?
+
+The NoSQL Java database is built for storing data locally, offline-first on resource-restricted devices like phones.
+
+The database is optimized for high speed and low resource consumption on restricted devices, making it ideal for use on mobile devices. It uses minimal CPU, RAM, and power, which is not only great for users but also for the environment.
-ObjectBox NoSQL Java database is built for storing data locally on mobile devices. It is optimized for high efficiency on restricted devices and uses minimal CPU and RAM. Being fully ACID-compliant, ObjectBox is faster than any alternative, outperforming SQLite and Realm across all CRUD (Create, Read, Update, Delete) operations. Check out our [Performance Benchmarking App repository](https://github.com/objectbox/objectbox-performance).
+Being fully ACID-compliant, ObjectBox is faster than any alternative, outperforming SQLite and Realm across all CRUD (Create, Read, Update, Delete) operations. Check out our [Performance Benchmarking App repository](https://github.com/objectbox/objectbox-performance).
-Additionally, our concise API is easy to learn and only requires a fraction of the code compared to SQLite. No more rows or columns, just plain objects with built-in relations.
+Our concise native-language API is easy to pick up and only requires a fraction of the code compared to SQLite. No more rows or columns, just plain objects (true POJOS) with built-in relations. It's great for handling large data volumes and allows changing your model whenever needed.
+
+All of this makes ObjectBox a smart choice for local data persistence with Java and Kotlin - it's efficient, easy and sustainable.
### Features
๐ **High performance** on restricted devices, like IoT gateways, micro controllers, ECUs etc.\
-๐ช **Resourceful** with minimal CPU, power and Memory usage for maximum flexibility and sustainability\
-๐ **Relations:** object links / relationships are built-in\
-๐ป **Multiplatform:** Linux, Windows, Android, iOS, macOS
+๐ **Resourceful** with minimal CPU, power and Memory usage for maximum flexibility and sustainability\
+๐ **[Relations](https://docs.objectbox.io/relations):** object links / relationships are built-in\
+๐ป **Multiplatform:** Linux, Windows, Android, iOS, macOS, any POSIX system
๐ฑ **Scalable:** handling millions of objects resource-efficiently with ease\
-๐ **Queries:** filter data as needed, even across relations\
+๐ **[Queries](https://docs.objectbox.io/queries):** filter data as needed, even across relations\
๐ฆฎ **Statically typed:** compile time checks & optimizations\
๐ **Automatic schema migrations:** no update scripts needed
@@ -70,9 +82,8 @@ Additionally, our concise API is easy to learn and only requires a fraction of t
๐ **[ObjectBox Sync](https://objectbox.io/sync/):** keeps data in sync between devices and servers\
๐ **[ObjectBox TS](https://objectbox.io/time-series-database/):** time series extension for time based data
-Enjoy โค๏ธ
-
-## Gradle setup
+## How to get started
+### Gradle setup
For Android projects, add the ObjectBox Gradle plugin to your root `build.gradle`:
@@ -100,7 +111,7 @@ plugins {
apply plugin: "io.objectbox" // Add after other plugins.
```
-## First steps
+### First steps
Create a data object class `@Entity`, for example "Playlist".
```
@@ -130,9 +141,9 @@ For details please check the [docs](https://docs.objectbox.io).
## Already using ObjectBox?
-We believe, ObjectBox is super easy to use. We are on a mission to make developersโ lives better, by building developer tools that are intuitive and fun to code with.
+โค **Your opinion matters to us!** Please fill in this 2-minute [Anonymous Feedback Form](https://forms.gle/bdktGBUmL4m48ruj7).
-To do that, we want your feedback: what do you love? What's amiss? Where do you struggle in everyday app development?
+We believe, ObjectBox is super easy to use. We want to bring joy and delight to app developers with intuitive and fun to code with APIs. To do that, we want your feedback: what do you love? What's amiss? Where do you struggle in everyday app development?
**We're looking forward to receiving your comments and requests:**
- Add [GitHub issues](https://github.com/ObjectBox/objectbox-java/issues)
@@ -149,10 +160,10 @@ Keep in touch: For general news on ObjectBox, [check our blog](https://objectbox
ObjectBox supports multiple platforms and languages.
Besides JVM based languages like Java and Kotlin, ObjectBox also offers:
-* [ObjectBox Swift Database](https://github.com/objectbox/objectbox-swift): build fast mobile apps for iOS (and macOS)
-* [ObjectBox Dart/Flutter Database](https://github.com/objectbox/objectbox-dart): cross-platform for mobile and desktop apps
-* [ObjectBox Go Database](https://github.com/objectbox/objectbox-go): great for data-driven tools and embedded server applications
-* [ObjectBox C and C++ Database](https://github.com/objectbox/objectbox-c): native speed with zero copy access to FlatBuffer objects
+* [Swift Database](https://github.com/objectbox/objectbox-swift): build fast mobile apps for iOS (and macOS)
+* [Dart/Flutter Database](https://github.com/objectbox/objectbox-dart): cross-platform for mobile and desktop apps
+* [Go Database](https://github.com/objectbox/objectbox-go): great for data-driven tools and embedded server applications
+* [C and C++ Database](https://github.com/objectbox/objectbox-c): native speed with zero copy access to FlatBuffer objects
## License
From a6a1b2d7577bae8d8fc5309538417d38b209e9f9 Mon Sep 17 00:00:00 2001
From: Anna Ivahnenko <91467067+ivahnenkoAnna@users.noreply.github.com>
Date: Fri, 16 Sep 2022 12:13:34 +0200
Subject: [PATCH 002/352] Update README.md
---
README.md | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index 5b4a5baf..2d9efa70 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,9 @@
-
+
+
+
From 48331e7a18fc1a780f73d413be347f1333779064 Mon Sep 17 00:00:00 2001
From: Markus
Date: Mon, 17 Oct 2022 14:50:02 +0200
Subject: [PATCH 003/352] Add maxDataSizeInKbyte to FlatStoreOptions, add
TreeOptionFlags
Also reapply: "Update SyncFlags: rename to DebugLogIdMapping, add ClientKeepDataOnSyncError"
---
.../java/io/objectbox/BoxStoreBuilder.java | 2 +-
.../io/objectbox/model/FlatStoreOptions.java | 25 +++++++---
.../io/objectbox/model/TreeOptionFlags.java | 49 +++++++++++++++++++
3 files changed, 68 insertions(+), 8 deletions(-)
create mode 100644 objectbox-java/src/main/java/io/objectbox/model/TreeOptionFlags.java
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
index 1497f1f6..5746b7f8 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
@@ -482,7 +482,7 @@ byte[] buildFlatStoreOptions(String canonicalPath) {
// ...then build options.
FlatStoreOptions.addDirectoryPath(fbb, directoryPathOffset);
- FlatStoreOptions.addMaxDbSizeInKByte(fbb, maxSizeInKByte);
+ FlatStoreOptions.addMaxDbSizeInKbyte(fbb, maxSizeInKByte);
FlatStoreOptions.addFileMode(fbb, fileMode);
FlatStoreOptions.addMaxReaders(fbb, maxReaders);
if (validateOnOpenMode != 0) {
diff --git a/objectbox-java/src/main/java/io/objectbox/model/FlatStoreOptions.java b/objectbox-java/src/main/java/io/objectbox/model/FlatStoreOptions.java
index 2443561a..a1c16662 100644
--- a/objectbox-java/src/main/java/io/objectbox/model/FlatStoreOptions.java
+++ b/objectbox-java/src/main/java/io/objectbox/model/FlatStoreOptions.java
@@ -57,7 +57,7 @@ public final class FlatStoreOptions extends Table {
* e.g. caused by programming error.
* If your app runs into errors like "db full", you may consider to raise the limit.
*/
- public long maxDbSizeInKByte() { int o = __offset(8); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+ public long maxDbSizeInKbyte() { int o = __offset(8); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
/**
* File permissions given in Unix style octal bit flags (e.g. 0644). Ignored on Windows.
* Note: directories become searchable if the "read" or "write" permission is set (e.g. 0640 becomes 0750).
@@ -135,11 +135,19 @@ public final class FlatStoreOptions extends Table {
* corner cases with e.g. transactions, which may not be fully tested at the moment.
*/
public boolean noReaderThreadLocals() { int o = __offset(30); return o != 0 ? 0!=bb.get(o + bb_pos) : false; }
+ /**
+ * Data size tracking is more involved than DB size tracking, e.g. it stores an internal counter.
+ * Thus only use it if a stricter, more accurate limit is required.
+ * It tracks the size of actual data bytes of objects (system and metadata is not considered).
+ * On the upside, reaching the data limit still allows data to be removed (assuming DB limit is not reached).
+ * Max data and DB sizes can be combined; data size must be below the DB size.
+ */
+ public long maxDataSizeInKbyte() { int o = __offset(32); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
public static int createFlatStoreOptions(FlatBufferBuilder builder,
int directoryPathOffset,
int modelBytesOffset,
- long maxDbSizeInKByte,
+ long maxDbSizeInKbyte,
long fileMode,
long maxReaders,
int validateOnOpen,
@@ -150,10 +158,12 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
boolean usePreviousCommitOnValidationFailure,
boolean readOnly,
long debugFlags,
- boolean noReaderThreadLocals) {
- builder.startTable(14);
+ boolean noReaderThreadLocals,
+ long maxDataSizeInKbyte) {
+ builder.startTable(15);
+ FlatStoreOptions.addMaxDataSizeInKbyte(builder, maxDataSizeInKbyte);
FlatStoreOptions.addValidateOnOpenPageLimit(builder, validateOnOpenPageLimit);
- FlatStoreOptions.addMaxDbSizeInKByte(builder, maxDbSizeInKByte);
+ FlatStoreOptions.addMaxDbSizeInKbyte(builder, maxDbSizeInKbyte);
FlatStoreOptions.addDebugFlags(builder, debugFlags);
FlatStoreOptions.addMaxReaders(builder, maxReaders);
FlatStoreOptions.addFileMode(builder, fileMode);
@@ -169,13 +179,13 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
return FlatStoreOptions.endFlatStoreOptions(builder);
}
- public static void startFlatStoreOptions(FlatBufferBuilder builder) { builder.startTable(14); }
+ public static void startFlatStoreOptions(FlatBufferBuilder builder) { builder.startTable(15); }
public static void addDirectoryPath(FlatBufferBuilder builder, int directoryPathOffset) { builder.addOffset(0, directoryPathOffset, 0); }
public static void addModelBytes(FlatBufferBuilder builder, int modelBytesOffset) { builder.addOffset(1, modelBytesOffset, 0); }
public static int createModelBytesVector(FlatBufferBuilder builder, byte[] data) { return builder.createByteVector(data); }
public static int createModelBytesVector(FlatBufferBuilder builder, ByteBuffer data) { return builder.createByteVector(data); }
public static void startModelBytesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
- public static void addMaxDbSizeInKByte(FlatBufferBuilder builder, long maxDbSizeInKByte) { builder.addLong(2, maxDbSizeInKByte, 0L); }
+ public static void addMaxDbSizeInKbyte(FlatBufferBuilder builder, long maxDbSizeInKbyte) { builder.addLong(2, maxDbSizeInKbyte, 0L); }
public static void addFileMode(FlatBufferBuilder builder, long fileMode) { builder.addInt(3, (int) fileMode, (int) 0L); }
public static void addMaxReaders(FlatBufferBuilder builder, long maxReaders) { builder.addInt(4, (int) maxReaders, (int) 0L); }
public static void addValidateOnOpen(FlatBufferBuilder builder, int validateOnOpen) { builder.addShort(5, (short) validateOnOpen, (short) 0); }
@@ -187,6 +197,7 @@ public static int createFlatStoreOptions(FlatBufferBuilder builder,
public static void addReadOnly(FlatBufferBuilder builder, boolean readOnly) { builder.addBoolean(11, readOnly, false); }
public static void addDebugFlags(FlatBufferBuilder builder, long debugFlags) { builder.addInt(12, (int) debugFlags, (int) 0L); }
public static void addNoReaderThreadLocals(FlatBufferBuilder builder, boolean noReaderThreadLocals) { builder.addBoolean(13, noReaderThreadLocals, false); }
+ public static void addMaxDataSizeInKbyte(FlatBufferBuilder builder, long maxDataSizeInKbyte) { builder.addLong(14, maxDataSizeInKbyte, 0L); }
public static int endFlatStoreOptions(FlatBufferBuilder builder) {
int o = builder.endTable();
return o;
diff --git a/objectbox-java/src/main/java/io/objectbox/model/TreeOptionFlags.java b/objectbox-java/src/main/java/io/objectbox/model/TreeOptionFlags.java
new file mode 100644
index 00000000..3184b3a0
--- /dev/null
+++ b/objectbox-java/src/main/java/io/objectbox/model/TreeOptionFlags.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 ObjectBox Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package io.objectbox.model;
+
+/**
+ * Options flags for trees.
+ */
+@SuppressWarnings("unused")
+public final class TreeOptionFlags {
+ private TreeOptionFlags() { }
+ /**
+ * If true, debug logs are always disabled for this tree regardless of the store's debug flags.
+ */
+ public static final int DebugLogsDisable = 1;
+ /**
+ * If true, debug logs are always enabled for this tree regardless of the store's debug flags.
+ */
+ public static final int DebugLogsEnable = 2;
+ /**
+ * By default, a path such as "a/b/c" can address a branch and a leaf at the same time.
+ * E.g. under the common parent path "a/b", a branch "c" and a "c" leaf may exist.
+ * To disable this, set this flag to true.
+ * This will enable an additional check when inserting new leafs and new branches for the existence of the other.
+ */
+ public static final int EnforceUniquePath = 4;
+ /**
+ * In some scenarios, e.g. when using Sync, multiple node objects of the same type (e.g. branch or leaf) at the
+ * same path may exist temporarily. By enabling this flag, this is not considered an error situation. Instead, the
+ * first node is picked.
+ */
+ public static final int AllowNonUniqueNodes = 8;
+}
+
From 29747e24f86cdfb04127017bcfa46255f7592699 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Mon, 17 Oct 2022 15:11:05 +0200
Subject: [PATCH 004/352] Query: add findFirstId and findUniqueId (#149)
---
.../exception/NonUniqueResultException.java | 6 ++-
.../main/java/io/objectbox/query/Query.java | 36 ++++++++++++++--
.../java/io/objectbox/query/QueryTest.java | 41 +++++++++++++++++--
3 files changed, 75 insertions(+), 8 deletions(-)
diff --git a/objectbox-java/src/main/java/io/objectbox/exception/NonUniqueResultException.java b/objectbox-java/src/main/java/io/objectbox/exception/NonUniqueResultException.java
index 4eb4dbdf..77907bb9 100644
--- a/objectbox-java/src/main/java/io/objectbox/exception/NonUniqueResultException.java
+++ b/objectbox-java/src/main/java/io/objectbox/exception/NonUniqueResultException.java
@@ -16,7 +16,11 @@
package io.objectbox.exception;
-/** Throw if {@link io.objectbox.query.Query#findUnique()} returns more than one result. */
+/**
+ * Thrown if {@link io.objectbox.query.Query#findUnique() Query.findUnique()} or
+ * {@link io.objectbox.query.Query#findUniqueId() Query.findUniqueId()} is called,
+ * but the query matches more than one object.
+ */
public class NonUniqueResultException extends DbException {
public NonUniqueResultException(String message) {
super(message);
diff --git a/objectbox-java/src/main/java/io/objectbox/query/Query.java b/objectbox-java/src/main/java/io/objectbox/query/Query.java
index 317ef310..7424f0e5 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/Query.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/Query.java
@@ -61,6 +61,10 @@ public class Query implements Closeable {
native List nativeFind(long handle, long cursorHandle, long offset, long limit) throws Exception;
+ native long nativeFindFirstId(long handle, long cursorHandle);
+
+ native long nativeFindUniqueId(long handle, long cursorHandle);
+
native long[] nativeFindIds(long handle, long cursorHandle, long offset, long limit);
native long nativeCount(long handle, long cursorHandle);
@@ -191,9 +195,9 @@ private void ensureNoComparator() {
}
/**
- * Find the unique Object matching the query.
- *
- * @throws io.objectbox.exception.NonUniqueResultException if result was not unique
+ * If there is a single matching object, returns it. If there is more than one matching object,
+ * throws {@link io.objectbox.exception.NonUniqueResultException NonUniqueResultException}.
+ * If there are no matches returns null.
*/
@Nullable
public T findUnique() {
@@ -244,6 +248,32 @@ public List find(final long offset, final long limit) {
});
}
+ /**
+ * Returns the ID of the first matching object. If there are no results returns 0.
+ *
+ * Like {@link #findFirst()}, but more efficient as no object is created.
+ *
+ * Ignores any {@link QueryBuilder#filter(QueryFilter) query filter}.
+ */
+ public long findFirstId() {
+ checkOpen();
+ return box.internalCallWithReaderHandle(cursorHandle -> nativeFindFirstId(handle, cursorHandle));
+ }
+
+ /**
+ * If there is a single matching object, returns its ID. If there is more than one matching object,
+ * throws {@link io.objectbox.exception.NonUniqueResultException NonUniqueResultException}.
+ * If there are no matches returns 0.
+ *
+ * Like {@link #findUnique()}, but more efficient as no object is created.
+ *
+ * Ignores any {@link QueryBuilder#filter(QueryFilter) query filter}.
+ */
+ public long findUniqueId() {
+ checkOpen();
+ return box.internalCallWithReaderHandle(cursorHandle -> nativeFindUniqueId(handle, cursorHandle));
+ }
+
/**
* Very efficient way to get just the IDs without creating any objects. IDs can later be used to lookup objects
* (lookups by ID are also very efficient in ObjectBox).
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryTest.java
index e043e3c5..6194d730 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryTest.java
@@ -104,14 +104,16 @@ public void useAfterQueryClose_fails() {
assertThrowsQueryIsClosed(query::count);
assertThrowsQueryIsClosed(query::describe);
assertThrowsQueryIsClosed(query::describeParameters);
+ assertThrowsQueryIsClosed(query::findFirst);
+ assertThrowsQueryIsClosed(query::findUnique);
assertThrowsQueryIsClosed(query::find);
assertThrowsQueryIsClosed(() -> query.find(0, 1));
- assertThrowsQueryIsClosed(query::findFirst);
+ assertThrowsQueryIsClosed(query::findFirstId);
+ assertThrowsQueryIsClosed(query::findUniqueId);
assertThrowsQueryIsClosed(query::findIds);
assertThrowsQueryIsClosed(() -> query.findIds(0, 1));
assertThrowsQueryIsClosed(query::findLazy);
assertThrowsQueryIsClosed(query::findLazyCached);
- assertThrowsQueryIsClosed(query::findUnique);
assertThrowsQueryIsClosed(query::remove);
// For setParameter(s) the native method is not actually called, so fine to use incorrect alias and property.
@@ -162,14 +164,16 @@ public void useAfterStoreClose_failsIfUsingStore() {
// All methods accessing the store throw.
assertThrowsStoreIsClosed(query::count);
+ assertThrowsStoreIsClosed(query::findFirst);
+ assertThrowsStoreIsClosed(query::findUnique);
assertThrowsStoreIsClosed(query::find);
assertThrowsStoreIsClosed(() -> query.find(0, 1));
- assertThrowsStoreIsClosed(query::findFirst);
+ assertThrowsStoreIsClosed(query::findFirstId);
+ assertThrowsStoreIsClosed(query::findUniqueId);
assertThrowsStoreIsClosed(query::findIds);
assertThrowsStoreIsClosed(() -> query.findIds(0, 1));
assertThrowsStoreIsClosed(query::findLazy);
assertThrowsStoreIsClosed(query::findLazyCached);
- assertThrowsStoreIsClosed(query::findUnique);
assertThrowsStoreIsClosed(query::remove);
assertThrowsStoreIsClosed(() -> query.subscribe().observer(data -> {
}));
@@ -915,6 +919,35 @@ public void testRemove() {
assertEquals(4, box.count());
}
+ @Test
+ public void findFirstId() {
+ putTestEntitiesScalars();
+ try (Query query = box.query(simpleInt.greater(2006)).build()) {
+ assertEquals(8, query.findFirstId());
+ }
+ // No result.
+ try (Query query = box.query(simpleInt.equal(-1)).build()) {
+ assertEquals(0, query.findFirstId());
+ }
+ }
+
+ @Test
+ public void findUniqueId() {
+ putTestEntitiesScalars();
+ try (Query query = box.query(simpleInt.equal(2006)).build()) {
+ assertEquals(7, query.findUniqueId());
+ }
+ // No result.
+ try (Query query = box.query(simpleInt.equal(-1)).build()) {
+ assertEquals(0, query.findUniqueId());
+ }
+ // More than one result.
+ try (Query query = box.query(simpleInt.greater(2006)).build()) {
+ NonUniqueResultException e = assertThrows(NonUniqueResultException.class, query::findUniqueId);
+ assertEquals("Query does not have a unique result (more than one result): 3", e.getMessage());
+ }
+ }
+
@Test
public void testFindIds() {
putTestEntitiesScalars();
From 32021fbb60d8623e7562a1b17b8a6e72126b9d45 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Mon, 17 Oct 2022 15:55:08 +0200
Subject: [PATCH 005/352] Store: add experimental maxDataSizeInKByte (#149)
---
.../java/io/objectbox/BoxStoreBuilder.java | 39 ++++++++--
.../DbMaxDataSizeExceededException.java | 27 +++++++
.../io/objectbox/BoxStoreBuilderTest.java | 73 ++++++++++++++++++-
3 files changed, 131 insertions(+), 8 deletions(-)
create mode 100644 objectbox-java/src/main/java/io/objectbox/exception/DbMaxDataSizeExceededException.java
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
index 5746b7f8..8fea90b2 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
@@ -77,6 +77,8 @@ public class BoxStoreBuilder {
/** Defaults to {@link #DEFAULT_MAX_DB_SIZE_KBYTE}. */
long maxSizeInKByte = DEFAULT_MAX_DB_SIZE_KBYTE;
+ long maxDataSizeInKByte;
+
/** On Android used for native library loading. */
@Nullable Object context;
@Nullable Object relinker;
@@ -339,10 +341,34 @@ BoxStoreBuilder modelUpdate(ModelUpdate modelUpdate) {
* (for example you insert data in an infinite loop).
*/
public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {
+ if (maxSizeInKByte <= maxDataSizeInKByte) {
+ throw new IllegalArgumentException("maxSizeInKByte must be larger than maxDataSizeInKByte.");
+ }
this.maxSizeInKByte = maxSizeInKByte;
return this;
}
+ /**
+ * This API is experimental and may change or be removed in future releases.
+ *
+ * Sets the maximum size the data stored in the database can grow to. Must be below {@link #maxSizeInKByte(long)}.
+ *
+ * Different from {@link #maxSizeInKByte(long)} this only counts bytes stored in objects, excluding system and
+ * metadata. However, it is more involved than database size tracking, e.g. it stores an internal counter.
+ * Only use this if a stricter, more accurate limit is required.
+ *
+ * When the data limit is reached data can be removed to get below the limit again (assuming the database size limit
+ * is not also reached).
+ */
+ @Experimental
+ public BoxStoreBuilder maxDataSizeInKByte(long maxDataSizeInKByte) {
+ if (maxDataSizeInKByte >= maxSizeInKByte) {
+ throw new IllegalArgumentException("maxDataSizeInKByte must be smaller than maxSizeInKByte.");
+ }
+ this.maxDataSizeInKByte = maxDataSizeInKByte;
+ return this;
+ }
+
/**
* Open the store in read-only mode: no schema update, no write transactions are allowed (would throw).
*/
@@ -491,13 +517,12 @@ byte[] buildFlatStoreOptions(String canonicalPath) {
FlatStoreOptions.addValidateOnOpenPageLimit(fbb, validateOnOpenPageLimit);
}
}
- if(skipReadSchema) FlatStoreOptions.addSkipReadSchema(fbb, skipReadSchema);
- if(usePreviousCommit) FlatStoreOptions.addUsePreviousCommit(fbb, usePreviousCommit);
- if(readOnly) FlatStoreOptions.addReadOnly(fbb, readOnly);
- if(noReaderThreadLocals) FlatStoreOptions.addNoReaderThreadLocals(fbb, noReaderThreadLocals);
- if (debugFlags != 0) {
- FlatStoreOptions.addDebugFlags(fbb, debugFlags);
- }
+ if (skipReadSchema) FlatStoreOptions.addSkipReadSchema(fbb, true);
+ if (usePreviousCommit) FlatStoreOptions.addUsePreviousCommit(fbb, true);
+ if (readOnly) FlatStoreOptions.addReadOnly(fbb, true);
+ if (noReaderThreadLocals) FlatStoreOptions.addNoReaderThreadLocals(fbb, true);
+ if (debugFlags != 0) FlatStoreOptions.addDebugFlags(fbb, debugFlags);
+ if (maxDataSizeInKByte > 0) FlatStoreOptions.addMaxDataSizeInKbyte(fbb, maxDataSizeInKByte);
int offset = FlatStoreOptions.endFlatStoreOptions(fbb);
fbb.finish(offset);
diff --git a/objectbox-java/src/main/java/io/objectbox/exception/DbMaxDataSizeExceededException.java b/objectbox-java/src/main/java/io/objectbox/exception/DbMaxDataSizeExceededException.java
new file mode 100644
index 00000000..b75a4927
--- /dev/null
+++ b/objectbox-java/src/main/java/io/objectbox/exception/DbMaxDataSizeExceededException.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 ObjectBox Ltd. All rights reserved.
+ *
+ * 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 io.objectbox.exception;
+
+/**
+ * Thrown when applying a transaction would exceed the {@link io.objectbox.BoxStoreBuilder#maxDataSizeInKByte(long) maxDataSizeInKByte}
+ * configured for the store.
+ */
+public class DbMaxDataSizeExceededException extends DbException {
+ public DbMaxDataSizeExceededException(String message) {
+ super(message);
+ }
+}
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/BoxStoreBuilderTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/BoxStoreBuilderTest.java
index 31fd64b8..3f099393 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/BoxStoreBuilderTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/BoxStoreBuilderTest.java
@@ -16,6 +16,8 @@
package io.objectbox;
+import io.objectbox.exception.DbFullException;
+import io.objectbox.exception.DbMaxDataSizeExceededException;
import io.objectbox.exception.PagesCorruptException;
import io.objectbox.model.ValidateOnOpenMode;
import org.greenrobot.essentials.io.IoUtils;
@@ -28,7 +30,6 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -38,6 +39,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -45,6 +47,8 @@ public class BoxStoreBuilderTest extends AbstractObjectBoxTest {
private BoxStoreBuilder builder;
+ private static final String LONG_STRING = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";
+
@Override
protected BoxStore createBoxStore() {
// Standard setup of store not required
@@ -167,6 +171,73 @@ public void readOnly() {
assertTrue(store.isReadOnly());
}
+ @Test
+ public void maxSize_invalidValues_throw() {
+ // Max data larger than max database size throws.
+ builder.maxSizeInKByte(10);
+ IllegalArgumentException exSmaller = assertThrows(
+ IllegalArgumentException.class,
+ () -> builder.maxDataSizeInKByte(11)
+ );
+ assertEquals("maxDataSizeInKByte must be smaller than maxSizeInKByte.", exSmaller.getMessage());
+
+ // Max database size smaller than max data size throws.
+ builder.maxDataSizeInKByte(9);
+ IllegalArgumentException exLarger = assertThrows(
+ IllegalArgumentException.class,
+ () -> builder.maxSizeInKByte(8)
+ );
+ assertEquals("maxSizeInKByte must be larger than maxDataSizeInKByte.", exLarger.getMessage());
+ }
+
+ @Test
+ public void maxFileSize() {
+ builder = createBoxStoreBuilder(null);
+ builder.maxSizeInKByte(30); // Empty file is around 12 KB, object below adds about 8 KB each.
+ store = builder.build();
+ putTestEntity(LONG_STRING, 1);
+ TestEntity testEntity2 = createTestEntity(LONG_STRING, 2);
+ DbFullException dbFullException = assertThrows(
+ DbFullException.class,
+ () -> getTestEntityBox().put(testEntity2)
+ );
+ assertEquals("Could not commit tx", dbFullException.getMessage());
+
+ // Re-open with larger size.
+ store.close();
+ builder.maxSizeInKByte(40);
+ store = builder.build();
+ testEntity2.setId(0); // Clear ID of object that failed to put.
+ getTestEntityBox().put(testEntity2);
+ }
+
+ @Test
+ public void maxDataSize() {
+ // Put until max data size is reached, but still below max database size.
+ builder = createBoxStoreBuilder(null);
+ builder.maxSizeInKByte(50); // Empty file is around 12 KB, each put adds about 8 KB.
+ builder.maxDataSizeInKByte(1);
+ store = builder.build();
+
+ TestEntity testEntity1 = putTestEntity(LONG_STRING, 1);
+ TestEntity testEntity2 = createTestEntity(LONG_STRING, 2);
+ DbMaxDataSizeExceededException maxDataExc = assertThrows(
+ DbMaxDataSizeExceededException.class,
+ () -> getTestEntityBox().put(testEntity2)
+ );
+ assertEquals("Exceeded user-set maximum by [bytes]: 64", maxDataExc.getMessage());
+
+ // Remove to get below max data size, then put again.
+ getTestEntityBox().remove(testEntity1);
+ getTestEntityBox().put(testEntity2);
+
+ // Alternatively, re-open with larger max data size.
+ store.close();
+ builder.maxDataSizeInKByte(2);
+ store = builder.build();
+ putTestEntity(LONG_STRING, 3);
+ }
+
@Test
public void validateOnOpen() {
// Create a database first; we must create the model only once (ID/UID sequences would be different 2nd time)
From b130dc2cb6ce03df37db6012b08fe15064d37273 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 18 Oct 2022 14:43:27 +0200
Subject: [PATCH 006/352] Update Kotlin (1.7.20) and libraries (dokka 1.7.20,
coroutines 1.6.4)
---
build.gradle.kts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index dea45ed9..55cc89bf 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -24,9 +24,9 @@ buildscript {
val essentialsVersion by extra("3.1.0")
val juniVersion by extra("4.13.2")
val mockitoVersion by extra("3.8.0")
- val kotlinVersion by extra("1.7.0")
- val coroutinesVersion by extra("1.6.2")
- val dokkaVersion by extra("1.6.10")
+ val kotlinVersion by extra("1.7.20")
+ val coroutinesVersion by extra("1.6.4")
+ val dokkaVersion by extra("1.7.20")
println("version=$obxJavaVersion")
println("objectboxNativeDependency=$obxJniLibVersion")
From 03125e92ad2432c9962c36a96a457f10e1446a97 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 18 Oct 2022 13:37:06 +0200
Subject: [PATCH 007/352] Prepare release 3.4.0
---
README.md | 2 +-
build.gradle.kts | 4 ++--
objectbox-java/src/main/java/io/objectbox/BoxStore.java | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 2d9efa70..274acbe3 100644
--- a/README.md
+++ b/README.md
@@ -91,7 +91,7 @@ For Android projects, add the ObjectBox Gradle plugin to your root `build.gradle
```groovy
buildscript {
- ext.objectboxVersion = "3.3.1"
+ ext.objectboxVersion = "3.4.0"
repositories {
mavenCentral()
}
diff --git a/build.gradle.kts b/build.gradle.kts
index 55cc89bf..a861dbd4 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,8 +1,8 @@
buildscript {
// Typically, only edit those two:
- val objectboxVersionNumber = "3.3.2" // without "-SNAPSHOT", e.g. "2.5.0" or "2.4.0-RC"
+ val objectboxVersionNumber = "3.4.0" // without "-SNAPSHOT", e.g. "2.5.0" or "2.4.0-RC"
val objectboxVersionRelease =
- false // set to true for releasing to ignore versionPostFix to avoid e.g. "-dev" versions
+ true // set to true for releasing to ignore versionPostFix to avoid e.g. "-dev" versions
// version post fix: "-" or "" if not defined; e.g. used by CI to pass in branch name
val versionPostFixValue = project.findProperty("versionPostFix")
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStore.java b/objectbox-java/src/main/java/io/objectbox/BoxStore.java
index 3ffc77f6..d745277b 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStore.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStore.java
@@ -69,9 +69,9 @@ public class BoxStore implements Closeable {
@Nullable private static Object relinker;
/** Change so ReLinker will update native library when using workaround loading. */
- public static final String JNI_VERSION = "3.3.1";
+ public static final String JNI_VERSION = "3.4.0";
- private static final String VERSION = "3.3.1-2022-09-05";
+ private static final String VERSION = "3.4.0-2022-10-18";
private static BoxStore defaultStore;
/** Currently used DB dirs with values from {@link #getCanonicalPath(File)}. */
From 19f64967ff64c1627e8c84e0dce73213ab6cdcef Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 18 Oct 2022 15:16:34 +0200
Subject: [PATCH 008/352] Fix JVM target warning for buildSrc project.
---
buildSrc/build.gradle.kts | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts
index 876c922b..b45c052a 100644
--- a/buildSrc/build.gradle.kts
+++ b/buildSrc/build.gradle.kts
@@ -5,3 +5,8 @@ plugins {
repositories {
mavenCentral()
}
+
+java {
+ sourceCompatibility = JavaVersion.VERSION_1_8
+ targetCompatibility = JavaVersion.VERSION_1_8
+}
From 85886e5c09384c10b64e62915b7048d442c0135e Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 18 Oct 2022 16:30:19 +0200
Subject: [PATCH 009/352] Start development of next version.
---
build.gradle.kts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build.gradle.kts b/build.gradle.kts
index a861dbd4..50beb4f0 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,8 +1,8 @@
buildscript {
// Typically, only edit those two:
- val objectboxVersionNumber = "3.4.0" // without "-SNAPSHOT", e.g. "2.5.0" or "2.4.0-RC"
+ val objectboxVersionNumber = "3.4.1" // without "-SNAPSHOT", e.g. "2.5.0" or "2.4.0-RC"
val objectboxVersionRelease =
- true // set to true for releasing to ignore versionPostFix to avoid e.g. "-dev" versions
+ false // set to true for releasing to ignore versionPostFix to avoid e.g. "-dev" versions
// version post fix: "-" or "" if not defined; e.g. used by CI to pass in branch name
val versionPostFixValue = project.findProperty("versionPostFix")
From fb745543d6f1a865b16b32a2b8aba99c5601847a Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Mon, 7 Nov 2022 14:30:12 +0100
Subject: [PATCH 010/352] Gradle: document supported project properties.
---
.gitlab-ci.yml | 3 +--
build.gradle.kts | 7 +++++++
.../src/main/kotlin/objectbox-publish.gradle.kts | 16 ++++++++++++++++
3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 58b31c18..10dfb8b2 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -5,8 +5,7 @@ image: objectboxio/buildenv:21.11.11-centos7
# - SONATYPE_USER
# - SONATYPE_PWD
# - GOOGLE_CHAT_WEBHOOK_JAVA_CI
-# Additionally, Gradle scripts assume these Gradle project properties are set:
-# https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties
+# Additionally, these environment variables used by the objectbox-publish Gradle script:
# - ORG_GRADLE_PROJECT_signingKeyFile
# - ORG_GRADLE_PROJECT_signingKeyId
# - ORG_GRADLE_PROJECT_signingPassword
diff --git a/build.gradle.kts b/build.gradle.kts
index 50beb4f0..a036b28a 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,3 +1,10 @@
+// This script supports some Gradle project properties:
+// https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties
+// - versionPostFix: appended to snapshot version number, e.g. "1.2.3--SNAPSHOT".
+// Use to create different versions based on branch/tag.
+// - sonatypeUsername: Maven Central credential used by Nexus publishing.
+// - sonatypePassword: Maven Central credential used by Nexus publishing.
+
buildscript {
// Typically, only edit those two:
val objectboxVersionNumber = "3.4.1" // without "-SNAPSHOT", e.g. "2.5.0" or "2.4.0-RC"
diff --git a/buildSrc/src/main/kotlin/objectbox-publish.gradle.kts b/buildSrc/src/main/kotlin/objectbox-publish.gradle.kts
index bc04e84e..1abc4b5c 100644
--- a/buildSrc/src/main/kotlin/objectbox-publish.gradle.kts
+++ b/buildSrc/src/main/kotlin/objectbox-publish.gradle.kts
@@ -1,3 +1,17 @@
+// This script requires some Gradle project properties to be set
+// (to set as environment variable prefix with ORG_GRADLE_PROJECT_):
+// https://docs.gradle.org/current/userguide/build_environment.html#sec:project_properties
+//
+// To publish artifacts to the internal GitLab repo set:
+// - gitlabUrl
+// - gitlabPrivateToken
+// - gitlabTokenName: optional, if set used instead of "Private-Token". Use for CI to specify e.g. "Job-Token".
+//
+// To sign artifacts using an ASCII encoded PGP key given via a file set:
+// - signingKeyFile
+// - signingKeyId
+// - signingPassword
+
plugins {
id("maven-publish")
id("signing")
@@ -73,6 +87,8 @@ publishing {
signing {
if (hasSigningProperties()) {
+ // Sign using an ASCII-armored key read from a file
+ // https://docs.gradle.org/current/userguide/signing_plugin.html#using_in_memory_ascii_armored_openpgp_subkeys
val signingKey = File(project.property("signingKeyFile").toString()).readText()
useInMemoryPgpKeys(
project.property("signingKeyId").toString(),
From 36bb1e22d580ee71f9ce7c7fcfd720d32b2d1fa8 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Mon, 7 Nov 2022 15:13:27 +0100
Subject: [PATCH 011/352] CI: do not publish from scheduled builds (#151)
---
.gitlab-ci.yml | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 10dfb8b2..7c4cdd71 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -120,6 +120,7 @@ upload-to-internal:
tags: [ docker, x64 ]
except:
- tags # Only publish from branches.
+ - schedules # Do not publish artifacts from scheduled jobs to save on disk space.
script:
- ./gradlew $GITLAB_REPO_ARGS $VERSION_ARGS publishMavenJavaPublicationToGitLabRepository
From 272719ea6242979d3de6fd0251841b35d6a03214 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 22 Nov 2022 14:21:49 +0100
Subject: [PATCH 012/352] Tests: RelationInfo fields are public.
---
.../src/main/java/io/objectbox/relation/Customer_.java | 4 ++--
.../src/main/java/io/objectbox/relation/Order_.java | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
index bcb28f40..7de3a98b 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
@@ -108,7 +108,7 @@ public long getId(Customer object) {
}
}
- static final RelationInfo orders =
+ public static final RelationInfo orders =
new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
@Override
public List getToMany(Customer customer) {
@@ -121,7 +121,7 @@ public ToOne getToOne(Order order) {
}
});
- static final RelationInfo ordersStandalone =
+ public static final RelationInfo ordersStandalone =
new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
@Override
public List getToMany(Customer customer) {
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
index 97bd5564..c84e094b 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
@@ -110,7 +110,7 @@ public long getId(Order object) {
}
}
- static final RelationInfo customer = new RelationInfo<>(Order_.__INSTANCE, Customer_.__INSTANCE, customerId, new ToOneGetter() {
+ public static final RelationInfo customer = new RelationInfo<>(Order_.__INSTANCE, Customer_.__INSTANCE, customerId, new ToOneGetter() {
@Override
public ToOne getToOne(Order object) {
return object.customer__toOne;
From c1727bfa44c16360997b62121d93b9945248eeb1 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 22 Nov 2022 14:57:29 +0100
Subject: [PATCH 013/352] Tests: update Order ToOne to how it should be used.
---
.../java/io/objectbox/relation/Customer.java | 5 ++--
.../java/io/objectbox/relation/Customer_.java | 2 +-
.../java/io/objectbox/relation/Order.java | 23 ++++---------------
.../io/objectbox/relation/OrderCursor.java | 5 ++--
.../java/io/objectbox/relation/Order_.java | 2 +-
.../relation/AbstractRelationTest.java | 2 +-
.../objectbox/relation/RelationEagerTest.java | 16 ++++++-------
.../io/objectbox/relation/RelationTest.java | 8 +++----
.../java/io/objectbox/relation/ToOneTest.java | 2 +-
9 files changed, 26 insertions(+), 39 deletions(-)
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer.java
index 8f6dc36b..1286ac7f 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer.java
@@ -20,6 +20,7 @@
import java.util.List;
import io.objectbox.BoxStore;
+import io.objectbox.annotation.Backlink;
import io.objectbox.annotation.Entity;
import io.objectbox.annotation.Id;
import io.objectbox.annotation.Index;
@@ -37,12 +38,12 @@ public class Customer implements Serializable {
@Index
private String name;
+ @Backlink(to = "customer") // Annotation not processed in this test, is set up manually.
List orders = new ToMany<>(this, Customer_.orders);
ToMany ordersStandalone = new ToMany<>(this, Customer_.ordersStandalone);
- /** Used to resolve relations */
- @Internal
+ /** Used to resolve relations. */
transient BoxStore __boxStore;
public Customer() {
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
index 7de3a98b..02a45bd3 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
@@ -117,7 +117,7 @@ public List getToMany(Customer customer) {
}, Order_.customerId, new ToOneGetter() {
@Override
public ToOne getToOne(Order order) {
- return order.customer__toOne;
+ return order.getCustomer();
}
});
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order.java
index 419d3cfc..b47efca6 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order.java
@@ -39,15 +39,12 @@ public class Order implements Serializable {
long customerId;
String text;
- private Customer customer;
+ @SuppressWarnings("FieldMayBeFinal")
+ private ToOne customer = new ToOne<>(this, Order_.customer);
- /** @Depreacted Used to resolve relations */
- @Internal
+ /** Used to resolve relations. */
transient BoxStore __boxStore;
- @Internal
- transient ToOne customer__toOne = new ToOne<>(this, Order_.customer);
-
public Order() {
}
@@ -94,20 +91,8 @@ public void setText(String text) {
this.text = text;
}
- public Customer peekCustomer() {
- return customer;
- }
-
- /** To-one relationship, resolved on first access. */
- public Customer getCustomer() {
- customer = customer__toOne.getTarget(this.customerId);
+ public ToOne getCustomer() {
return customer;
}
- /** Set the to-one relation including its ID property. */
- public void setCustomer(@Nullable Customer customer) {
- customer__toOne.setTarget(customer);
- this.customer = customer;
- }
-
}
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/OrderCursor.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/OrderCursor.java
index d2eea268..cb885e00 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/OrderCursor.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/OrderCursor.java
@@ -59,10 +59,11 @@ public long getId(Order entity) {
*/
@Override
public long put(Order entity) {
- if(entity.customer__toOne.internalRequiresPutTarget()) {
+ ToOne customer = entity.getCustomer();
+ if(customer != null && customer.internalRequiresPutTarget()) {
Cursor targetCursor = getRelationTargetCursor(Customer.class);
try {
- entity.customer__toOne.internalPutTarget(targetCursor);
+ customer.internalPutTarget(targetCursor);
} finally {
targetCursor.close();
}
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
index c84e094b..e2742d77 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
@@ -113,7 +113,7 @@ public long getId(Order object) {
public static final RelationInfo customer = new RelationInfo<>(Order_.__INSTANCE, Customer_.__INSTANCE, customerId, new ToOneGetter() {
@Override
public ToOne getToOne(Order object) {
- return object.customer__toOne;
+ return object.getCustomer();
}
});
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/AbstractRelationTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/AbstractRelationTest.java
index 65ee0e91..03a00217 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/AbstractRelationTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/AbstractRelationTest.java
@@ -64,7 +64,7 @@ protected Customer putCustomer() {
protected Order putOrder(@Nullable Customer customer, @Nullable String text) {
Order order = new Order();
- order.setCustomer(customer);
+ order.getCustomer().setTarget(customer);
order.setText(text);
orderBox.put(order);
return order;
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationEagerTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationEagerTest.java
index b3a6a51c..7e95b3f2 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationEagerTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationEagerTest.java
@@ -94,20 +94,20 @@ public void testEagerToSingle() {
// full list
List orders = orderBox.query().eager(Order_.customer).build().find();
assertEquals(2, orders.size());
- assertTrue(orders.get(0).customer__toOne.isResolved());
- assertTrue(orders.get(1).customer__toOne.isResolved());
+ assertTrue(orders.get(0).getCustomer().isResolved());
+ assertTrue(orders.get(1).getCustomer().isResolved());
// full list paginated
orders = orderBox.query().eager(Order_.customer).build().find(0, 10);
assertEquals(2, orders.size());
- assertTrue(orders.get(0).customer__toOne.isResolved());
- assertTrue(orders.get(1).customer__toOne.isResolved());
+ assertTrue(orders.get(0).getCustomer().isResolved());
+ assertTrue(orders.get(1).getCustomer().isResolved());
// list with eager limit
orders = orderBox.query().eager(1, Order_.customer).build().find();
assertEquals(2, orders.size());
- assertTrue(orders.get(0).customer__toOne.isResolved());
- assertFalse(orders.get(1).customer__toOne.isResolved());
+ assertTrue(orders.get(0).getCustomer().isResolved());
+ assertFalse(orders.get(1).getCustomer().isResolved());
// forEach
final int[] count = {0};
@@ -119,12 +119,12 @@ public void testEagerToSingle() {
// first
Order order = orderBox.query().eager(Order_.customer).build().findFirst();
- assertTrue(order.customer__toOne.isResolved());
+ assertTrue(order.getCustomer().isResolved());
// unique
orderBox.remove(order);
order = orderBox.query().eager(Order_.customer).build().findUnique();
- assertTrue(order.customer__toOne.isResolved());
+ assertTrue(order.getCustomer().isResolved());
}
@Test
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationTest.java
index 8bb4ff08..818890bf 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/RelationTest.java
@@ -37,9 +37,9 @@ public void testRelationToOne() {
Order order1 = orderBox.get(order.getId());
assertEquals(customer.getId(), order1.getCustomerId());
- assertNull(order1.peekCustomer());
- assertEquals(customer.getId(), order1.getCustomer().getId());
- assertNotNull(order1.peekCustomer());
+ assertNull(order1.getCustomer().getCachedTarget());
+ assertEquals(customer.getId(), order1.getCustomer().getTarget().getId());
+ assertNotNull(order1.getCustomer().getCachedTarget());
}
@Test
@@ -85,7 +85,7 @@ public void testRelationToMany_activeRelationshipChanges() {
((ToMany) orders).reset();
assertEquals(1, orders.size());
- order2.setCustomer(null);
+ order2.getCustomer().setTarget(null);
orderBox.put(order2);
((ToMany) orders).reset();
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/ToOneTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/ToOneTest.java
index 86be8fa7..3fad733f 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/relation/ToOneTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/relation/ToOneTest.java
@@ -100,7 +100,7 @@ public void testPutNewSourceAndTarget() {
Customer target = new Customer();
target.setName("target1");
- ToOne toOne = source.customer__toOne;
+ ToOne toOne = source.getCustomer();
assertTrue(toOne.isResolved());
assertTrue(toOne.isNull());
assertNull(toOne.getCachedTarget());
From afd04fe28397c8d022061ec73f6a9d22784db58f Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 29 Nov 2022 12:26:55 +0100
Subject: [PATCH 014/352] Unify import order, javadoc and code formatting.
---
.../src/main/java/io/objectbox/Box.java | 6 +++-
.../src/main/java/io/objectbox/BoxStore.java | 30 +++++++++----------
.../java/io/objectbox/BoxStoreBuilder.java | 14 ++++-----
.../main/java/io/objectbox/ModelBuilder.java | 3 +-
.../io/objectbox/ObjectClassPublisher.java | 8 +++--
.../src/main/java/io/objectbox/Property.java | 20 ++++++++-----
.../main/java/io/objectbox/Transaction.java | 2 +-
.../io/objectbox/ideasonly/ModelModifier.java | 2 +-
.../io/objectbox/internal/DebugCursor.java | 2 +-
.../java/io/objectbox/internal/Feature.java | 2 +-
.../internal/NativeLibraryLoader.java | 13 ++++----
.../internal/ObjectBoxThreadPool.java | 1 -
.../io/objectbox/query/PropertyQuery.java | 16 +++++-----
.../main/java/io/objectbox/query/Query.java | 4 +--
.../java/io/objectbox/query/QueryBuilder.java | 19 ++++++------
.../io/objectbox/query/QueryPublisher.java | 1 +
.../objectbox/reactive/DataTransformer.java | 1 +
.../reactive/SubscriptionBuilder.java | 2 +-
.../io/objectbox/relation/RelationInfo.java | 2 +-
.../java/io/objectbox/relation/ToMany.java | 6 ++--
.../objectbox/sync/ObjectsMessageBuilder.java | 4 +--
.../src/main/java/io/objectbox/sync/Sync.java | 1 -
.../java/io/objectbox/sync/SyncClient.java | 19 +++++++-----
.../io/objectbox/sync/SyncClientImpl.java | 13 ++++----
.../objectbox/sync/SyncCredentialsToken.java | 9 +++---
.../sync/listener/SyncChangeListener.java | 1 +
.../java/io/objectbox/sync/package-info.java | 10 +++----
.../sync/server/SyncServerBuilder.java | 13 ++++----
.../objectbox/sync/server/SyncServerImpl.java | 6 ++--
29 files changed, 123 insertions(+), 107 deletions(-)
diff --git a/objectbox-java/src/main/java/io/objectbox/Box.java b/objectbox-java/src/main/java/io/objectbox/Box.java
index 0cf8da69..7d2f0a85 100644
--- a/objectbox-java/src/main/java/io/objectbox/Box.java
+++ b/objectbox-java/src/main/java/io/objectbox/Box.java
@@ -302,6 +302,7 @@ public boolean isEmpty() {
/**
* Returns all stored Objects in this Box.
+ *
* @return since 2.4 the returned list is always mutable (before an empty result list was immutable)
*/
public List getAll() {
@@ -320,8 +321,9 @@ public List getAll() {
/**
* Check if an object with the given ID exists in the database.
* This is more efficient than a {@link #get(long)} and comparing against null.
+ *
+ * @return true if an object with the given ID was found, false otherwise.
* @since 2.7
- * @return true if a object with the given ID was found, false otherwise
*/
public boolean contains(long id) {
Cursor reader = getReader();
@@ -425,6 +427,7 @@ public void putBatched(@Nullable Collection entities, int batchSize) {
/**
* Removes (deletes) the Object by its ID.
+ *
* @return true if an entity was actually removed (false if no entity exists with the given ID)
*/
public boolean remove(long id) {
@@ -486,6 +489,7 @@ public void removeByIds(@Nullable Collection ids) {
/**
* Removes (deletes) the given Object.
+ *
* @return true if an entity was actually removed (false if no entity exists with the given ID)
*/
public boolean remove(T object) {
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStore.java b/objectbox-java/src/main/java/io/objectbox/BoxStore.java
index d745277b..ebd4a31c 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStore.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStore.java
@@ -16,9 +16,6 @@
package io.objectbox;
-import io.objectbox.internal.Feature;
-import org.greenrobot.essentials.collections.LongHashMap;
-
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
@@ -49,12 +46,14 @@
import io.objectbox.exception.DbException;
import io.objectbox.exception.DbExceptionListener;
import io.objectbox.exception.DbSchemaException;
+import io.objectbox.internal.Feature;
import io.objectbox.internal.NativeLibraryLoader;
import io.objectbox.internal.ObjectBoxThreadPool;
import io.objectbox.reactive.DataObserver;
import io.objectbox.reactive.DataPublisher;
import io.objectbox.reactive.SubscriptionBuilder;
import io.objectbox.sync.SyncClient;
+import org.greenrobot.essentials.collections.LongHashMap;
/**
* An ObjectBox database that provides {@link Box Boxes} to put and get objects of specific entity classes
@@ -267,7 +266,7 @@ public static boolean isSyncServerAvailable() {
try {
handle = nativeCreateWithFlatOptions(builder.buildFlatStoreOptions(canonicalPath), builder.model);
- if(handle == 0) throw new DbException("Could not create native store");
+ if (handle == 0) throw new DbException("Could not create native store");
int debugFlags = builder.debugFlags;
if (debugFlags != 0) {
@@ -539,7 +538,7 @@ public Transaction beginTx() {
System.out.println("Begin TX with commit count " + initialCommitCount);
}
long nativeTx = nativeBeginTx(handle);
- if(nativeTx == 0) throw new DbException("Could not create native transaction");
+ if (nativeTx == 0) throw new DbException("Could not create native transaction");
Transaction tx = new Transaction(this, nativeTx, initialCommitCount);
synchronized (transactions) {
@@ -565,7 +564,7 @@ public Transaction beginReadTx() {
System.out.println("Begin read TX with commit count " + initialCommitCount);
}
long nativeTx = nativeBeginReadTx(handle);
- if(nativeTx == 0) throw new DbException("Could not create native read transaction");
+ if (nativeTx == 0) throw new DbException("Could not create native read transaction");
Transaction tx = new Transaction(this, nativeTx, initialCommitCount);
synchronized (transactions) {
@@ -601,7 +600,7 @@ public void close() {
synchronized (this) {
oldClosedState = closed;
if (!closed) {
- if(objectBrowserPort != 0) { // not linked natively (yet), so clean up here
+ if (objectBrowserPort != 0) { // not linked natively (yet), so clean up here
try {
stopObjectBrowser();
} catch (Throwable e) {
@@ -679,7 +678,7 @@ public boolean deleteAllFiles() {
* BoxStoreBuilder#DEFAULT_NAME})".
*
* @param objectStoreDirectory directory to be deleted; this is the value you previously provided to {@link
- * BoxStoreBuilder#directory(File)}
+ * BoxStoreBuilder#directory(File)}
* @return true if the directory 1) was deleted successfully OR 2) did not exist in the first place.
* Note: If false is returned, any number of files may have been deleted before the failure happened.
* @throws IllegalStateException if the given directory is still used by a open {@link BoxStore}.
@@ -715,9 +714,9 @@ public static boolean deleteAllFiles(File objectStoreDirectory) {
* If you did not use a custom name with BoxStoreBuilder, you can pass "new File({@link
* BoxStoreBuilder#DEFAULT_NAME})".
*
- * @param androidContext provide an Android Context like Application or Service
+ * @param androidContext provide an Android Context like Application or Service
* @param customDbNameOrNull use null for default name, or the name you previously provided to {@link
- * BoxStoreBuilder#name(String)}.
+ * BoxStoreBuilder#name(String)}.
* @return true if the directory 1) was deleted successfully OR 2) did not exist in the first place.
* Note: If false is returned, any number of files may have been deleted before the failure happened.
* @throws IllegalStateException if the given name is still used by a open {@link BoxStore}.
@@ -736,9 +735,9 @@ public static boolean deleteAllFiles(Object androidContext, @Nullable String cus
* BoxStoreBuilder#DEFAULT_NAME})".
*
* @param baseDirectoryOrNull use null for no base dir, or the value you previously provided to {@link
- * BoxStoreBuilder#baseDirectory(File)}
- * @param customDbNameOrNull use null for default name, or the name you previously provided to {@link
- * BoxStoreBuilder#name(String)}.
+ * BoxStoreBuilder#baseDirectory(File)}
+ * @param customDbNameOrNull use null for default name, or the name you previously provided to {@link
+ * BoxStoreBuilder#name(String)}.
* @return true if the directory 1) was deleted successfully OR 2) did not exist in the first place.
* Note: If false is returned, any number of files may have been deleted before the failure happened.
* @throws IllegalStateException if the given directory (+name) is still used by a open {@link BoxStore}.
@@ -1055,8 +1054,9 @@ public String diagnose() {
/**
* Validate database pages, a lower level storage unit (integrity check).
* Do not call this inside a transaction (currently unsupported).
+ *
* @param pageLimit the maximum of pages to validate (e.g. to limit time spent on validation).
- * Pass zero set no limit and thus validate all pages.
+ * Pass zero set no limit and thus validate all pages.
* @param checkLeafLevel Flag to validate leaf pages. These do not point to other pages but contain data.
* @return Number of pages validated, which may be twice the given pageLimit as internally there are "two DBs".
* @throws DbException if validation failed to run (does not tell anything about DB file consistency).
@@ -1172,7 +1172,7 @@ public String startObjectBrowser(String urlToBindTo) {
@Experimental
public synchronized boolean stopObjectBrowser() {
- if(objectBrowserPort == 0) {
+ if (objectBrowserPort == 0) {
throw new IllegalStateException("ObjectBrowser has not been started before");
}
objectBrowserPort = 0;
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
index 8fea90b2..c8bc6666 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
@@ -16,10 +16,6 @@
package io.objectbox;
-import io.objectbox.flatbuffers.FlatBufferBuilder;
-
-import org.greenrobot.essentials.io.IoUtils;
-
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -38,9 +34,11 @@
import io.objectbox.annotation.apihint.Experimental;
import io.objectbox.annotation.apihint.Internal;
import io.objectbox.exception.DbException;
+import io.objectbox.flatbuffers.FlatBufferBuilder;
import io.objectbox.ideasonly.ModelUpdate;
import io.objectbox.model.FlatStoreOptions;
import io.objectbox.model.ValidateOnOpenMode;
+import org.greenrobot.essentials.io.IoUtils;
/**
* Configures and builds a {@link BoxStore} with reasonable defaults. To get an instance use {@code MyObjectBox.builder()}.
@@ -299,7 +297,7 @@ public BoxStoreBuilder fileMode(int mode) {
* amount of threads you are using.
* For highly concurrent setups (e.g. you are using ObjectBox on the server side) it may make sense to increase the
* number.
- *
+ *
* Note: Each thread that performed a read transaction and is still alive holds on to a reader slot.
* These slots only get vacated when the thread ends. Thus, be mindful with the number of active threads.
* Alternatively, you can opt to try the experimental noReaderThreadLocals option flag.
@@ -312,9 +310,9 @@ public BoxStoreBuilder maxReaders(int maxReaders) {
/**
* Disables the usage of thread locals for "readers" related to read transactions.
* This can make sense if you are using a lot of threads that are kept alive.
- *
+ *
* Note: This is still experimental, as it comes with subtle behavior changes at a low level and may affect
- * corner cases with e.g. transactions, which may not be fully tested at the moment.
+ * corner cases with e.g. transactions, which may not be fully tested at the moment.
*/
public BoxStoreBuilder noReaderThreadLocals() {
this.noReaderThreadLocals = true;
@@ -527,7 +525,7 @@ byte[] buildFlatStoreOptions(String canonicalPath) {
int offset = FlatStoreOptions.endFlatStoreOptions(fbb);
fbb.finish(offset);
return fbb.sizedByteArray();
- }
+ }
/**
* Builds a {@link BoxStore} using any given configuration.
diff --git a/objectbox-java/src/main/java/io/objectbox/ModelBuilder.java b/objectbox-java/src/main/java/io/objectbox/ModelBuilder.java
index 9784b972..a872b7ca 100644
--- a/objectbox-java/src/main/java/io/objectbox/ModelBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/ModelBuilder.java
@@ -16,14 +16,13 @@
package io.objectbox;
-import io.objectbox.flatbuffers.FlatBufferBuilder;
-
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import io.objectbox.annotation.apihint.Internal;
+import io.objectbox.flatbuffers.FlatBufferBuilder;
import io.objectbox.model.IdUid;
import io.objectbox.model.Model;
import io.objectbox.model.ModelEntity;
diff --git a/objectbox-java/src/main/java/io/objectbox/ObjectClassPublisher.java b/objectbox-java/src/main/java/io/objectbox/ObjectClassPublisher.java
index cf6e9127..2f528d04 100644
--- a/objectbox-java/src/main/java/io/objectbox/ObjectClassPublisher.java
+++ b/objectbox-java/src/main/java/io/objectbox/ObjectClassPublisher.java
@@ -16,9 +16,6 @@
package io.objectbox;
-import org.greenrobot.essentials.collections.MultimapSet;
-import org.greenrobot.essentials.collections.MultimapSet.SetType;
-
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Collections;
@@ -32,6 +29,8 @@
import io.objectbox.reactive.DataPublisher;
import io.objectbox.reactive.DataPublisherUtils;
import io.objectbox.reactive.SubscriptionBuilder;
+import org.greenrobot.essentials.collections.MultimapSet;
+import org.greenrobot.essentials.collections.MultimapSet.SetType;
/**
* A {@link DataPublisher} that notifies {@link DataObserver}s about changes in an entity box.
@@ -45,14 +44,17 @@ class ObjectClassPublisher implements DataPublisher, Runnable {
final BoxStore boxStore;
final MultimapSet> observersByEntityTypeId = MultimapSet.create(SetType.THREAD_SAFE);
private final Deque changesQueue = new ArrayDeque<>();
+
private static class PublishRequest {
@Nullable private final DataObserver observer;
private final int[] entityTypeIds;
+
PublishRequest(@Nullable DataObserver observer, int[] entityTypeIds) {
this.observer = observer;
this.entityTypeIds = entityTypeIds;
}
}
+
volatile boolean changePublisherRunning;
ObjectClassPublisher(BoxStore boxStore) {
diff --git a/objectbox-java/src/main/java/io/objectbox/Property.java b/objectbox-java/src/main/java/io/objectbox/Property.java
index d151f4f6..835a4f75 100644
--- a/objectbox-java/src/main/java/io/objectbox/Property.java
+++ b/objectbox-java/src/main/java/io/objectbox/Property.java
@@ -16,6 +16,12 @@
package io.objectbox;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Date;
+
+import javax.annotation.Nullable;
+
import io.objectbox.annotation.apihint.Internal;
import io.objectbox.converter.PropertyConverter;
import io.objectbox.exception.DbException;
@@ -34,11 +40,6 @@
import io.objectbox.query.PropertyQueryConditionImpl.StringStringCondition;
import io.objectbox.query.QueryBuilder.StringOrder;
-import javax.annotation.Nullable;
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.Date;
-
/**
* Meta data describing a Property of an ObjectBox Entity.
* Properties are typically used when defining {@link io.objectbox.query.Query Query} conditions
@@ -60,7 +61,8 @@ public class Property implements Serializable {
public final boolean isId;
public final boolean isVirtual;
public final String dbName;
- @SuppressWarnings("rawtypes") // Use raw type of PropertyConverter to allow users to supply a generic implementation.
+ @SuppressWarnings("rawtypes")
+ // Use raw type of PropertyConverter to allow users to supply a generic implementation.
public final Class extends PropertyConverter> converterClass;
/** Type, which is converted to a type supported by the DB. */
@@ -83,14 +85,16 @@ public Property(EntityInfo entity, int ordinal, int id, Class> type, S
this(entity, ordinal, id, type, name, isId, dbName, null, null);
}
- @SuppressWarnings("rawtypes") // Use raw type of PropertyConverter to allow users to supply a generic implementation.
+ @SuppressWarnings("rawtypes")
+ // Use raw type of PropertyConverter to allow users to supply a generic implementation.
public Property(EntityInfo entity, int ordinal, int id, Class> type, String name, boolean isId,
@Nullable String dbName, @Nullable Class extends PropertyConverter> converterClass,
@Nullable Class> customType) {
this(entity, ordinal, id, type, name, isId, false, dbName, converterClass, customType);
}
- @SuppressWarnings("rawtypes") // Use raw type of PropertyConverter to allow users to supply a generic implementation.
+ @SuppressWarnings("rawtypes")
+ // Use raw type of PropertyConverter to allow users to supply a generic implementation.
public Property(EntityInfo entity, int ordinal, int id, Class> type, String name, boolean isId,
boolean isVirtual, @Nullable String dbName,
@Nullable Class extends PropertyConverter> converterClass, @Nullable Class> customType) {
diff --git a/objectbox-java/src/main/java/io/objectbox/Transaction.java b/objectbox-java/src/main/java/io/objectbox/Transaction.java
index b3ba8906..5e2035f7 100644
--- a/objectbox-java/src/main/java/io/objectbox/Transaction.java
+++ b/objectbox-java/src/main/java/io/objectbox/Transaction.java
@@ -184,7 +184,7 @@ public Cursor createCursor(Class entityClass) {
EntityInfo entityInfo = store.getEntityInfo(entityClass);
CursorFactory factory = entityInfo.getCursorFactory();
long cursorHandle = nativeCreateCursor(transaction, entityInfo.getDbName(), entityClass);
- if(cursorHandle == 0) throw new DbException("Could not create native cursor");
+ if (cursorHandle == 0) throw new DbException("Could not create native cursor");
return factory.createCursor(this, cursorHandle, store);
}
diff --git a/objectbox-java/src/main/java/io/objectbox/ideasonly/ModelModifier.java b/objectbox-java/src/main/java/io/objectbox/ideasonly/ModelModifier.java
index b25ab938..158c3b22 100644
--- a/objectbox-java/src/main/java/io/objectbox/ideasonly/ModelModifier.java
+++ b/objectbox-java/src/main/java/io/objectbox/ideasonly/ModelModifier.java
@@ -35,7 +35,7 @@ public void remove() {
}
public PropertyModifier property(String name) {
- return new PropertyModifier(this, name);
+ return new PropertyModifier(this, name);
}
}
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/DebugCursor.java b/objectbox-java/src/main/java/io/objectbox/internal/DebugCursor.java
index dd53dbd0..0134ff10 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/DebugCursor.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/DebugCursor.java
@@ -42,7 +42,7 @@ public class DebugCursor implements Closeable {
public static DebugCursor create(Transaction tx) {
long txHandle = InternalAccess.getHandle(tx);
long handle = nativeCreate(txHandle);
- if(handle == 0) throw new DbException("Could not create native debug cursor");
+ if (handle == 0) throw new DbException("Could not create native debug cursor");
return new DebugCursor(tx, handle);
}
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/Feature.java b/objectbox-java/src/main/java/io/objectbox/internal/Feature.java
index 99ca6f67..48fd3544 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/Feature.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/Feature.java
@@ -11,7 +11,7 @@ public enum Feature {
/** TimeSeries support (date/date-nano companion ID and other time-series functionality). */
TIME_SERIES(2),
- /** Sync client availability. Visit the ObjectBox Sync website for more details. */
+ /** Sync client availability. Visit the ObjectBox Sync website for more details. */
SYNC(3),
/** Check whether debug log can be enabled during runtime. */
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/NativeLibraryLoader.java b/objectbox-java/src/main/java/io/objectbox/internal/NativeLibraryLoader.java
index b7373ced..a9da606a 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/NativeLibraryLoader.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/NativeLibraryLoader.java
@@ -16,11 +16,6 @@
package io.objectbox.internal;
-import io.objectbox.BoxStore;
-import org.greenrobot.essentials.io.IoUtils;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
@@ -37,6 +32,12 @@
import java.net.URLConnection;
import java.util.Arrays;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import io.objectbox.BoxStore;
+import org.greenrobot.essentials.io.IoUtils;
+
/**
* Separate class, so we can mock BoxStore.
*/
@@ -162,7 +163,7 @@ private static String getCpuArch() {
String cpuArchOS = cpuArchOSOrNull.toLowerCase();
if (cpuArchOS.startsWith("armv7")) {
cpuArch = "armv7";
- } else if (cpuArchOS.startsWith("armv6")){
+ } else if (cpuArchOS.startsWith("armv6")) {
cpuArch = "armv6";
} // else use fall back below.
} // else use fall back below.
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/ObjectBoxThreadPool.java b/objectbox-java/src/main/java/io/objectbox/internal/ObjectBoxThreadPool.java
index 41b2ccdd..e47c78af 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/ObjectBoxThreadPool.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/ObjectBoxThreadPool.java
@@ -33,7 +33,6 @@
*
Reduce keep-alive time for threads to 20 seconds
*
Uses a ThreadFactory to name threads like "ObjectBox-1-Thread-1"
*
- *
*/
@Internal
public class ObjectBoxThreadPool extends ThreadPoolExecutor {
diff --git a/objectbox-java/src/main/java/io/objectbox/query/PropertyQuery.java b/objectbox-java/src/main/java/io/objectbox/query/PropertyQuery.java
index 9ddc5100..b5ee8fab 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/PropertyQuery.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/PropertyQuery.java
@@ -347,10 +347,10 @@ public Double findDouble() {
/**
* Sums up all values for the given property over all Objects matching the query.
- *
+ *
* Note: this method is not recommended for properties of type long unless you know the contents of the DB not to
- * overflow. Use {@link #sumDouble()} instead if you cannot guarantee the sum to be in the long value range.
- *
+ * overflow. Use {@link #sumDouble()} instead if you cannot guarantee the sum to be in the long value range.
+ *
* @return 0 in case no elements matched the query
* @throws io.objectbox.exception.NumericOverflowException if the sum exceeds the numbers {@link Long} can
* represent.
@@ -362,11 +362,11 @@ public long sum() {
);
}
- /**
+ /**
* Sums up all values for the given property over all Objects matching the query.
- *
+ *
* Note: for integer types int and smaller, {@link #sum()} is usually preferred for sums.
- *
+ *
* @return 0 in case no elements matched the query
*/
public double sumDouble() {
@@ -386,9 +386,9 @@ public long max() {
);
}
- /**
+ /**
* Finds the maximum value for the given property over all Objects matching the query.
- *
+ *
* @return NaN in case no elements matched the query
*/
public double maxDouble() {
diff --git a/objectbox-java/src/main/java/io/objectbox/query/Query.java b/objectbox-java/src/main/java/io/objectbox/query/Query.java
index 7424f0e5..c427e87e 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/Query.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/Query.java
@@ -117,7 +117,7 @@ native void nativeSetParameter(long handle, int entityId, int propertyId, @Nulla
// volatile so checkOpen() is more up-to-date (no need for synchronized; it's a race anyway)
volatile long handle;
- Query(Box box, long queryHandle, @Nullable List> eagerRelations, @Nullable QueryFilter filter,
+ Query(Box box, long queryHandle, @Nullable List> eagerRelations, @Nullable QueryFilter filter,
@Nullable Comparator comparator) {
this.box = box;
store = box.getStore();
@@ -282,7 +282,7 @@ public long findUniqueId() {
*/
@Nonnull
public long[] findIds() {
- return findIds(0,0);
+ return findIds(0, 0);
}
/**
diff --git a/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java b/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
index bf3a01cf..61588c14 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
@@ -16,20 +16,21 @@
package io.objectbox.query;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
import io.objectbox.Box;
import io.objectbox.EntityInfo;
import io.objectbox.Property;
import io.objectbox.annotation.apihint.Experimental;
import io.objectbox.annotation.apihint.Internal;
-import io.objectbox.exception.DbException;
+import io.objectbox.exception .DbException;
import io.objectbox.relation.RelationInfo;
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.List;
-
/**
* Builds a {@link Query Query} using conditions which can then be used to return a list of matching Objects.
*
@@ -216,7 +217,7 @@ public QueryBuilder(Box box, long storeHandle, String entityName) {
this.box = box;
this.storeHandle = storeHandle;
handle = nativeCreate(storeHandle, entityName);
- if(handle == 0) throw new DbException("Could not create native query builder");
+ if (handle == 0) throw new DbException("Could not create native query builder");
isSubQuery = false;
}
@@ -266,7 +267,7 @@ public Query build() {
throw new IllegalStateException("Incomplete logic condition. Use or()/and() between two conditions only.");
}
long queryHandle = nativeBuild(handle);
- if(queryHandle == 0) throw new DbException("Could not create native query");
+ if (queryHandle == 0) throw new DbException("Could not create native query");
Query query = new Query<>(box, queryHandle, eagerRelations, filter, comparator);
close();
return query;
diff --git a/objectbox-java/src/main/java/io/objectbox/query/QueryPublisher.java b/objectbox-java/src/main/java/io/objectbox/query/QueryPublisher.java
index a3d2196e..8b36f32e 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/QueryPublisher.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/QueryPublisher.java
@@ -55,6 +55,7 @@ private static class SubscribedObservers implements DataObserver> {
public void onData(List data) {
}
}
+
/** Placeholder observer to use if all subscribed observers should be notified. */
private final SubscribedObservers SUBSCRIBED_OBSERVERS = new SubscribedObservers<>();
diff --git a/objectbox-java/src/main/java/io/objectbox/reactive/DataTransformer.java b/objectbox-java/src/main/java/io/objectbox/reactive/DataTransformer.java
index d34f1cea..a5b41649 100644
--- a/objectbox-java/src/main/java/io/objectbox/reactive/DataTransformer.java
+++ b/objectbox-java/src/main/java/io/objectbox/reactive/DataTransformer.java
@@ -33,6 +33,7 @@
public interface DataTransformer {
/**
* Transforms/processes the given data.
+ *
* @param source data to be transformed
* @return transformed data
* @throws Exception Transformers may throw any exceptions, which can be reacted on via
diff --git a/objectbox-java/src/main/java/io/objectbox/reactive/SubscriptionBuilder.java b/objectbox-java/src/main/java/io/objectbox/reactive/SubscriptionBuilder.java
index 12b9373e..78bb7c7a 100644
--- a/objectbox-java/src/main/java/io/objectbox/reactive/SubscriptionBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/reactive/SubscriptionBuilder.java
@@ -167,7 +167,7 @@ public DataSubscription observer(DataObserver observer) {
weakObserver.setSubscription(subscription);
}
- if(dataSubscriptionList != null) {
+ if (dataSubscriptionList != null) {
dataSubscriptionList.add(subscription);
}
diff --git a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
index 09386908..7ca36aad 100644
--- a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
+++ b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
@@ -94,7 +94,7 @@ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo
* ToMany as a ToMany backlink
*/
public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
- ToManyGetter backlinkToManyGetter, int targetRelationId) {
+ ToManyGetter backlinkToManyGetter, int targetRelationId) {
this.sourceInfo = sourceInfo;
this.targetInfo = targetInfo;
this.toManyGetter = toManyGetter;
diff --git a/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java b/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
index 79b4e19f..ac3f43de 100644
--- a/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
+++ b/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
@@ -15,7 +15,6 @@
*/
package io.objectbox.relation;
-import io.objectbox.internal.ToManyGetter;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -42,6 +41,7 @@
import io.objectbox.exception.DbDetachedException;
import io.objectbox.internal.IdGetter;
import io.objectbox.internal.ReflectionCache;
+import io.objectbox.internal.ToManyGetter;
import io.objectbox.internal.ToOneGetter;
import io.objectbox.query.QueryFilter;
import io.objectbox.relation.ListFactory.CopyOnWriteArrayListFactory;
@@ -695,7 +695,7 @@ public boolean internalCheckApplyToDbRequired() {
}
private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter idGetter,
- @Nullable Map setAdded, @Nullable Map setRemoved) {
+ @Nullable Map setAdded, @Nullable Map setRemoved) {
ToManyGetter backlinkToManyGetter = relationInfo.backlinkToManyGetter;
synchronized (this) {
@@ -739,7 +739,7 @@ private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter idGetter,
- @Nullable Map setAdded, @Nullable Map setRemoved) {
+ @Nullable Map setAdded, @Nullable Map setRemoved) {
ToOneGetter backlinkToOneGetter = relationInfo.backlinkToOneGetter;
synchronized (this) {
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/ObjectsMessageBuilder.java b/objectbox-java/src/main/java/io/objectbox/sync/ObjectsMessageBuilder.java
index 60f9d7f5..5b29fbd9 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/ObjectsMessageBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/ObjectsMessageBuilder.java
@@ -1,10 +1,10 @@
package io.objectbox.sync;
/**
- * @see SyncClient#startObjectsMessage
+ * @see SyncClient#startObjectsMessage
*/
public interface ObjectsMessageBuilder {
-
+
ObjectsMessageBuilder addString(long optionalId, String value);
ObjectsMessageBuilder addBytes(long optionalId, byte[] value, boolean isFlatBuffers);
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/Sync.java b/objectbox-java/src/main/java/io/objectbox/sync/Sync.java
index 8d839c97..1e40a289 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/Sync.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/Sync.java
@@ -1,7 +1,6 @@
package io.objectbox.sync;
import io.objectbox.BoxStore;
-import io.objectbox.annotation.apihint.Experimental;
import io.objectbox.sync.server.SyncServerBuilder;
/**
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java b/objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java
index 04c9bccb..60b2fb47 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/SyncClient.java
@@ -1,5 +1,9 @@
package io.objectbox.sync;
+import java.io.Closeable;
+
+import javax.annotation.Nullable;
+
import io.objectbox.annotation.apihint.Experimental;
import io.objectbox.sync.SyncBuilder.RequestUpdatesMode;
import io.objectbox.sync.listener.SyncChangeListener;
@@ -9,12 +13,9 @@
import io.objectbox.sync.listener.SyncLoginListener;
import io.objectbox.sync.listener.SyncTimeListener;
-import javax.annotation.Nullable;
-import java.io.Closeable;
-
/**
* ObjectBox sync client. Build a client with {@link Sync#client}.
- *
+ *
* Keep the instance around (avoid garbage collection) while you want to have sync ongoing.
* For a clean shutdown, call {@link #close()}.
*
@@ -48,8 +49,9 @@ public interface SyncClient extends Closeable {
/**
* Estimates the current server timestamp in nanoseconds based on the last known server time.
+ *
* @return unix timestamp in nanoseconds (since epoch);
- * or 0 if there has not been a server contact yet and thus the server's time is unknown
+ * or 0 if there has not been a server contact yet and thus the server's time is unknown
*/
long getServerTimeNanos();
@@ -60,7 +62,7 @@ public interface SyncClient extends Closeable {
* except for when the server time is unknown, then the result is zero.
*
* @return time difference in nanoseconds; e.g. positive if server time is ahead of local time;
- * or 0 if there has not been a server contact yet and thus the server's time is unknown
+ * or 0 if there has not been a server contact yet and thus the server's time is unknown
*/
long getServerTimeDiffNanos();
@@ -69,7 +71,7 @@ public interface SyncClient extends Closeable {
* This is measured during login.
*
* @return roundtrip time in nanoseconds;
- * or 0 if there has not been a server contact yet and thus the roundtrip time could not be estimated
+ * or 0 if there has not been a server contact yet and thus the roundtrip time could not be estimated
*/
long getRoundtripTimeNanos();
@@ -148,9 +150,9 @@ public interface SyncClient extends Closeable {
* This is useful if sync updates were turned off with
* {@link SyncBuilder#requestUpdatesMode(RequestUpdatesMode) requestUpdatesMode(MANUAL)}.
*
- * @see #cancelUpdates()
* @return 'true' if the request was likely sent (e.g. the sync client is in "logged in" state)
* or 'false' if the request was not sent (and will not be sent in the future)
+ * @see #cancelUpdates()
*/
boolean requestUpdates();
@@ -158,6 +160,7 @@ public interface SyncClient extends Closeable {
* Asks the server to send sync updates until this sync client is up-to-date, then pauses sync updates again.
* This is useful if sync updates were turned off with
* {@link SyncBuilder#requestUpdatesMode(RequestUpdatesMode) requestUpdatesMode(MANUAL)}.
+ *
* @return 'true' if the request was likely sent (e.g. the sync client is in "logged in" state)
* or 'false' if the request was not sent (and will not be sent in the future)
*/
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java b/objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java
index b98f86dd..6e662350 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/SyncClientImpl.java
@@ -1,5 +1,10 @@
package io.objectbox.sync;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Nullable;
+
import io.objectbox.BoxStore;
import io.objectbox.InternalAccess;
import io.objectbox.annotation.apihint.Experimental;
@@ -12,10 +17,6 @@
import io.objectbox.sync.listener.SyncLoginListener;
import io.objectbox.sync.listener.SyncTimeListener;
-import javax.annotation.Nullable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
/**
* Internal sync client implementation. Use {@link SyncClient} to access functionality,
* this class may change without notice.
@@ -322,8 +323,8 @@ public ObjectsMessageBuilder startObjectsMessage(long flags, @Nullable String to
private native boolean nativeCancelUpdates(long handle);
/**
- * Hints to the native client that an active network connection is available.
- * Returns true if the native client was disconnected (and will try to re-connect).
+ * Hints to the native client that an active network connection is available.
+ * Returns true if the native client was disconnected (and will try to re-connect).
*/
private native boolean nativeTriggerReconnect(long handle);
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/SyncCredentialsToken.java b/objectbox-java/src/main/java/io/objectbox/sync/SyncCredentialsToken.java
index 7cff538b..de6d6140 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/SyncCredentialsToken.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/SyncCredentialsToken.java
@@ -1,11 +1,12 @@
package io.objectbox.sync;
-import io.objectbox.annotation.apihint.Internal;
-
-import javax.annotation.Nullable;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
+import javax.annotation.Nullable;
+
+import io.objectbox.annotation.apihint.Internal;
+
/**
* Internal credentials implementation. Use {@link SyncCredentials} to build credentials.
*/
@@ -47,7 +48,7 @@ public byte[] getTokenBytes() {
/**
* Clear after usage.
- *
+ *
* Note that actual data is not removed from memory until the next garbage collector run.
* Anyhow, the credentials are still kept in memory by the native component.
*/
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/listener/SyncChangeListener.java b/objectbox-java/src/main/java/io/objectbox/sync/listener/SyncChangeListener.java
index d1149d44..750e3c32 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/listener/SyncChangeListener.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/listener/SyncChangeListener.java
@@ -15,6 +15,7 @@
public interface SyncChangeListener {
// Note: this method is expected by JNI, check before modifying/removing it.
+
/**
* Called each time when data from sync was applied locally.
*
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/package-info.java b/objectbox-java/src/main/java/io/objectbox/sync/package-info.java
index 6b972231..7e40170c 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/package-info.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/package-info.java
@@ -20,17 +20,17 @@
*
* These are the typical steps to setup a sync client:
*
- *
Create a BoxStore as usual (using MyObjectBox)
- *
Get a {@link io.objectbox.sync.SyncBuilder} using {@link io.objectbox.sync.Sync#client(
- * io.objectbox.BoxStore, java.lang.String, io.objectbox.sync.SyncCredentials)}.
- * Here you need to pass the {@link io.objectbox.BoxStore}, along with an URL to the sync destination (server),
+ *
Create a BoxStore as usual (using MyObjectBox).
+ *
Get a {@link io.objectbox.sync.SyncBuilder} using
+ * {@link io.objectbox.sync.Sync#client(io.objectbox.BoxStore, java.lang.String, io.objectbox.sync.SyncCredentials) Sync.client(boxStore, url, credentials)}.
+ * Here you need to pass the {@link io.objectbox.BoxStore BoxStore}, along with an URL to the sync destination (server),
* and credentials. For demo set ups, you could start with {@link io.objectbox.sync.SyncCredentials#none()}
* credentials.
*
Optional: use the {@link io.objectbox.sync.SyncBuilder} instance from the last step to configure the sync
* client and set initial listeners.
*
Call {@link io.objectbox.sync.SyncBuilder#build()} to get an instance of
* {@link io.objectbox.sync.SyncClient} (and hold on to it). Synchronization is now active.
- *
Optional: Interact with {@link io.objectbox.sync.SyncClient}
+ *
Optional: Interact with {@link io.objectbox.sync.SyncClient}.
*
*/
@ParametersAreNonnullByDefault
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerBuilder.java b/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerBuilder.java
index b06d22d9..5664ea47 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerBuilder.java
@@ -1,13 +1,14 @@
package io.objectbox.sync.server;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
import io.objectbox.BoxStore;
import io.objectbox.annotation.apihint.Experimental;
-import io.objectbox.sync.listener.SyncChangeListener;
import io.objectbox.sync.SyncCredentials;
-
-import javax.annotation.Nullable;
-import java.util.ArrayList;
-import java.util.List;
+import io.objectbox.sync.listener.SyncChangeListener;
/**
* Creates a {@link SyncServer} and allows to set additional configuration.
@@ -80,7 +81,7 @@ public SyncServerBuilder peer(String url, SyncCredentials credentials) {
/**
* Builds and returns a Sync server ready to {@link SyncServer#start()}.
- *
+ *
* Note: this clears all previously set authenticator credentials.
*/
public SyncServer build() {
diff --git a/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerImpl.java b/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerImpl.java
index 0a011a14..76d4a80a 100644
--- a/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerImpl.java
+++ b/objectbox-java/src/main/java/io/objectbox/sync/server/SyncServerImpl.java
@@ -1,12 +1,12 @@
package io.objectbox.sync.server;
+import javax.annotation.Nullable;
+
import io.objectbox.InternalAccess;
import io.objectbox.annotation.apihint.Internal;
-import io.objectbox.sync.listener.SyncChangeListener;
import io.objectbox.sync.SyncCredentials;
import io.objectbox.sync.SyncCredentialsToken;
-
-import javax.annotation.Nullable;
+import io.objectbox.sync.listener.SyncChangeListener;
/**
* Internal sync server implementation. Use {@link SyncServer} to access functionality,
From 3fdf345b97c5a7b3aa1ea75af5441102671cd813 Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 22 Nov 2022 15:33:18 +0100
Subject: [PATCH 015/352] Query: add relation count condition (#150)
---
.../java/io/objectbox/query/QueryBuilder.java | 10 ++++
.../query/RelationCountCondition.java | 20 ++++++++
.../io/objectbox/relation/RelationInfo.java | 28 +++++++++++
.../query/QueryRelationCountTest.java | 50 +++++++++++++++++++
4 files changed, 108 insertions(+)
create mode 100644 objectbox-java/src/main/java/io/objectbox/query/RelationCountCondition.java
create mode 100644 tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryRelationCountTest.java
diff --git a/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java b/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
index 61588c14..173d831e 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/QueryBuilder.java
@@ -152,6 +152,9 @@ private native long nativeLink(long handle, long storeHandle, int relationOwnerE
private native void nativeSetParameterAlias(long conditionHandle, String alias);
+ private native long nativeRelationCount(long handle, long storeHandle, int relationOwnerEntityId, int propertyId,
+ int relationCount);
+
// ------------------------------ (Not)Null------------------------------
private native long nativeNull(long handle, int propertyId);
@@ -582,6 +585,13 @@ public QueryBuilder notNull(Property property) {
return this;
}
+ public QueryBuilder relationCount(RelationInfo relationInfo, int relationCount) {
+ verifyHandle();
+ checkCombineCondition(nativeRelationCount(handle, storeHandle, relationInfo.targetInfo.getEntityId(),
+ relationInfo.targetIdProperty.id, relationCount));
+ return this;
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Integers
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/objectbox-java/src/main/java/io/objectbox/query/RelationCountCondition.java b/objectbox-java/src/main/java/io/objectbox/query/RelationCountCondition.java
new file mode 100644
index 00000000..c0b80ef2
--- /dev/null
+++ b/objectbox-java/src/main/java/io/objectbox/query/RelationCountCondition.java
@@ -0,0 +1,20 @@
+package io.objectbox.query;
+
+import io.objectbox.relation.RelationInfo;
+
+public class RelationCountCondition extends QueryConditionImpl {
+
+ private final RelationInfo relationInfo;
+ private final int relationCount;
+
+
+ public RelationCountCondition(RelationInfo relationInfo, int relationCount) {
+ this.relationInfo = relationInfo;
+ this.relationCount = relationCount;
+ }
+
+ @Override
+ void apply(QueryBuilder builder) {
+ builder.relationCount(relationInfo, relationCount);
+ }
+}
diff --git a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
index 7ca36aad..a1f70592 100644
--- a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
+++ b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
@@ -25,6 +25,8 @@
import io.objectbox.annotation.apihint.Internal;
import io.objectbox.internal.ToManyGetter;
import io.objectbox.internal.ToOneGetter;
+import io.objectbox.query.QueryCondition;
+import io.objectbox.query.RelationCountCondition;
/**
* Meta info describing a relation including source and target entity.
@@ -130,5 +132,31 @@ public boolean isBacklink() {
public String toString() {
return "RelationInfo from " + sourceInfo.getEntityClass() + " to " + targetInfo.getEntityClass();
}
+
+ /**
+ * Creates a condition to match objects that have {@code relationCount} related objects pointing to them.
+ *
+ * {@code relationCount} may be 0 to match objects that do not have related objects.
+ * It typically should be a low number.
+ *
+ * This condition has some limitations:
+ *
+ *
only 1:N (ToMany using @Backlink) relations are supported,
+ *
the complexity is {@code O(n * (relationCount + 1))} and cannot be improved via indexes,
+ *
the relation count cannot be changed with setParameter once the query is built.
+ *
+ */
+ public QueryCondition relationCount(int relationCount) {
+ if (targetIdProperty == null) {
+ throw new IllegalStateException("The relation count condition is only supported for 1:N (ToMany using @Backlink) relations.");
+ }
+ return new RelationCountCondition<>(this, relationCount);
+ }
}
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryRelationCountTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryRelationCountTest.java
new file mode 100644
index 00000000..665849cf
--- /dev/null
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryRelationCountTest.java
@@ -0,0 +1,50 @@
+package io.objectbox.query;
+
+import io.objectbox.relation.AbstractRelationTest;
+import io.objectbox.relation.Customer;
+import io.objectbox.relation.Customer_;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class QueryRelationCountTest extends AbstractRelationTest {
+
+ @Test
+ public void queryRelationCount() {
+ // Customer without orders.
+ putCustomer();
+ // Customer with 2 orders.
+ Customer customerWithOrders = putCustomer();
+ putOrder(customerWithOrders, "First order");
+ putOrder(customerWithOrders, "Second order");
+
+ // Find customer with no orders.
+ try (Query query = customerBox
+ .query(Customer_.orders.relationCount(0))
+ .build()) {
+ List customer = query.find();
+ assertEquals(1, customer.size());
+ assertEquals(0, customer.get(0).getOrders().size());
+ }
+
+ // Find customer with two orders.
+ try (Query query = customerBox
+ .query(Customer_.orders.relationCount(2))
+ .build()) {
+ List customer = query.find();
+ assertEquals(1, customer.size());
+ assertEquals(2, customer.get(0).getOrders().size());
+ }
+
+ // Find no customer with three orders.
+ try (Query query = customerBox
+ .query(Customer_.orders.relationCount(3))
+ .build()) {
+ List customer = query.find();
+ assertEquals(0, customer.size());
+ }
+ }
+
+}
From 4262c5d9dbac500e99cff6196bfa8d6802238b74 Mon Sep 17 00:00:00 2001
From: greenrobot Team
Date: Tue, 12 Nov 2019 12:47:45 +0100
Subject: [PATCH 016/352] Query clone: add copy method to clone the native
query (#34)
---
.../main/java/io/objectbox/query/Query.java | 33 ++++++++
.../io/objectbox/query/QueryCopyTest.java | 82 +++++++++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
diff --git a/objectbox-java/src/main/java/io/objectbox/query/Query.java b/objectbox-java/src/main/java/io/objectbox/query/Query.java
index c427e87e..e316b6e0 100644
--- a/objectbox-java/src/main/java/io/objectbox/query/Query.java
+++ b/objectbox-java/src/main/java/io/objectbox/query/Query.java
@@ -55,6 +55,9 @@ public class Query implements Closeable {
native void nativeDestroy(long handle);
+ /** Clones the native query, incl. conditions and parameters, and returns a handle to the clone. */
+ native long nativeClone(long handle);
+
native Object nativeFindFirst(long handle, long cursorHandle);
native Object nativeFindUnique(long handle, long cursorHandle);
@@ -129,6 +132,20 @@ native void nativeSetParameter(long handle, int entityId, int propertyId, @Nulla
this.comparator = comparator;
}
+ /**
+ * Creates a copy of the {@code originalQuery}, but pointing to a different native query using {@code handle}.
+ */
+ // Note: not using recommended copy constructor (just passing this) as handle needs to change.
+ private Query(Query originalQuery, long handle) {
+ this(
+ originalQuery.box,
+ handle,
+ originalQuery.eagerRelations,
+ originalQuery.filter,
+ originalQuery.comparator
+ );
+ }
+
/**
* Explicitly call {@link #close()} instead to avoid expensive finalization.
*/
@@ -156,6 +173,22 @@ public synchronized void close() {
}
}
+ /**
+ * Creates a copy of this for use in another thread.
+ *
+ * Clones the native query, keeping any previously set parameters.
+ *
+ * Closing the original query does not close the copy. {@link #close()} the copy once finished using it.
+ *
+ * Note: a set {@link QueryBuilder#filter(QueryFilter) filter} or {@link QueryBuilder#sort(Comparator) sort}
+ * order must be thread safe.
+ */
+ // Note: not overriding clone() to avoid confusion with Java's cloning mechanism.
+ public Query copy() {
+ long cloneHandle = nativeClone(handle);
+ return new Query<>(this, cloneHandle);
+ }
+
/** To be called inside a read TX */
long cursorHandle() {
return InternalAccess.getActiveTxCursorHandle(box);
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
new file mode 100644
index 00000000..996619bc
--- /dev/null
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
@@ -0,0 +1,82 @@
+package io.objectbox.query;
+
+import io.objectbox.TestEntity;
+import io.objectbox.TestEntity_;
+import org.junit.Test;
+
+import java.util.Comparator;
+import java.util.List;
+
+import static org.junit.Assert.*;
+
+public class QueryCopyTest extends AbstractQueryTest {
+
+ @Test
+ public void queryCopy_isClone() {
+ putTestEntity("orange", 1);
+ TestEntity banana = putTestEntity("banana", 2);
+ putTestEntity("apple", 3);
+ TestEntity bananaMilkShake = putTestEntity("banana milk shake", 4);
+ putTestEntity("pineapple", 5);
+ putTestEntity("papaya", 6);
+
+ // Only even nr: 2, 4, 6.
+ QueryFilter filter = entity -> entity.getSimpleInt() % 2 == 0;
+ // Reverse insert order: 6, 4, 2.
+ Comparator comparator = Comparator.comparingLong(testEntity -> -testEntity.getId());
+
+ Query queryOriginal = box.query(TestEntity_.simpleString.contains("").alias("fruit"))
+ .filter(filter)
+ .sort(comparator)
+ .build();
+ // Only bananas: 4, 2.
+ queryOriginal.setParameter("fruit", banana.getSimpleString());
+
+ Query queryCopy = queryOriginal.copy();
+
+ // Object instances and native query handle should differ.
+ assertNotEquals(queryOriginal, queryCopy);
+ assertNotEquals(queryOriginal.handle, queryCopy.handle);
+
+ // Verify results are identical.
+ List resultsOriginal = queryOriginal.find();
+ queryOriginal.close();
+ List resultsCopy = queryCopy.find();
+ queryCopy.close();
+ assertEquals(2, resultsOriginal.size());
+ assertEquals(2, resultsCopy.size());
+ assertTestEntityEquals(bananaMilkShake, resultsOriginal.get(0));
+ assertTestEntityEquals(bananaMilkShake, resultsCopy.get(0));
+ assertTestEntityEquals(banana, resultsOriginal.get(1));
+ assertTestEntityEquals(banana, resultsCopy.get(1));
+ }
+
+ @Test
+ public void queryCopy_setParameter_noEffectOriginal() {
+ TestEntity orange = putTestEntity("orange", 1);
+ TestEntity banana = putTestEntity("banana", 2);
+
+ Query queryOriginal = box
+ .query(TestEntity_.simpleString.equal(orange.getSimpleString()).alias("fruit"))
+ .build();
+
+ // Set parameter on clone that changes result.
+ Query queryCopy = queryOriginal.copy()
+ .setParameter("fruit", banana.getSimpleString());
+
+ List resultsOriginal = queryOriginal.find();
+ queryOriginal.close();
+ assertEquals(1, resultsOriginal.size());
+ assertTestEntityEquals(orange, resultsOriginal.get(0));
+
+ List resultsCopy = queryCopy.find();
+ queryCopy.close();
+ assertEquals(1, resultsCopy.size());
+ assertTestEntityEquals(banana, resultsCopy.get(0));
+ }
+
+ private void assertTestEntityEquals(TestEntity expected, TestEntity actual) {
+ assertEquals(expected.getId(), actual.getId());
+ assertEquals(expected.getSimpleString(), actual.getSimpleString());
+ }
+}
From f6e435ed9f5ffe8c2ded7853e5fd969c96cad4a4 Mon Sep 17 00:00:00 2001
From: greenrobot Team
Date: Tue, 12 Nov 2019 14:36:49 +0100
Subject: [PATCH 017/352] Query clone: add a QueryThreadLocal and test (#34)
---
.../io/objectbox/query/QueryThreadLocal.java | 22 ++++++++++++
.../io/objectbox/query/QueryCopyTest.java | 34 +++++++++++++++++++
2 files changed, 56 insertions(+)
create mode 100644 objectbox-java/src/main/java/io/objectbox/query/QueryThreadLocal.java
diff --git a/objectbox-java/src/main/java/io/objectbox/query/QueryThreadLocal.java b/objectbox-java/src/main/java/io/objectbox/query/QueryThreadLocal.java
new file mode 100644
index 00000000..9bef4ec5
--- /dev/null
+++ b/objectbox-java/src/main/java/io/objectbox/query/QueryThreadLocal.java
@@ -0,0 +1,22 @@
+package io.objectbox.query;
+
+/**
+ * A {@link ThreadLocal} that, given an original {@link Query} object,
+ * returns a {@link Query#copy() copy}, for each thread.
+ */
+public class QueryThreadLocal extends ThreadLocal> {
+
+ private final Query original;
+
+ /**
+ * See {@link QueryThreadLocal}.
+ */
+ public QueryThreadLocal(Query original) {
+ this.original = original;
+ }
+
+ @Override
+ protected Query initialValue() {
+ return original.copy();
+ }
+}
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
index 996619bc..f6859d26 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/query/QueryCopyTest.java
@@ -6,6 +6,9 @@
import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.*;
@@ -79,4 +82,35 @@ private void assertTestEntityEquals(TestEntity expected, TestEntity actual) {
assertEquals(expected.getId(), actual.getId());
assertEquals(expected.getSimpleString(), actual.getSimpleString());
}
+
+ @Test
+ public void queryThreadLocal() throws InterruptedException {
+ Query queryOriginal = box.query().build();
+ QueryThreadLocal threadLocal = new QueryThreadLocal<>(queryOriginal);
+
+ AtomicReference> queryThreadAtomic = new AtomicReference<>();
+ CountDownLatch latch = new CountDownLatch(1);
+ new Thread(() -> {
+ queryThreadAtomic.set(threadLocal.get());
+ latch.countDown();
+ }).start();
+
+ assertTrue(latch.await(1, TimeUnit.SECONDS));
+
+ Query queryThread = queryThreadAtomic.get();
+ Query queryMain = threadLocal.get();
+
+ // Assert that initialValue returns something.
+ assertNotNull(queryThread);
+ assertNotNull(queryMain);
+
+ // Assert that initialValue returns clones.
+ assertNotEquals(queryThread.handle, queryOriginal.handle);
+ assertNotEquals(queryMain.handle, queryOriginal.handle);
+ assertNotEquals(queryThread.handle, queryMain.handle);
+
+ queryOriginal.close();
+ queryMain.close();
+ queryThread.close();
+ }
}
From e109699f3eaece836d25b7008cf2a12ed54fc32c Mon Sep 17 00:00:00 2001
From: Uwe <13865709+greenrobot-team@users.noreply.github.com>
Date: Tue, 29 Nov 2022 15:51:04 +0100
Subject: [PATCH 018/352] DbFullException: add docs, note that max size can be
changed (#164)
---
.../java/io/objectbox/BoxStoreBuilder.java | 21 +++++++++++++------
.../objectbox/exception/DbFullException.java | 4 ++++
2 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
index c8bc6666..e8b4259c 100644
--- a/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
+++ b/objectbox-java/src/main/java/io/objectbox/BoxStoreBuilder.java
@@ -34,6 +34,8 @@
import io.objectbox.annotation.apihint.Experimental;
import io.objectbox.annotation.apihint.Internal;
import io.objectbox.exception.DbException;
+import io.objectbox.exception.DbFullException;
+import io.objectbox.exception.DbMaxDataSizeExceededException;
import io.objectbox.flatbuffers.FlatBufferBuilder;
import io.objectbox.ideasonly.ModelUpdate;
import io.objectbox.model.FlatStoreOptions;
@@ -333,10 +335,13 @@ BoxStoreBuilder modelUpdate(ModelUpdate modelUpdate) {
/**
* Sets the maximum size the database file can grow to.
- * By default this is 1 GB, which should be sufficient for most applications.
+ * When applying a transaction (e.g. putting an object) would exceed it a {@link DbFullException} is thrown.
*
- * In general, a maximum size prevents the DB from growing indefinitely when something goes wrong
- * (for example you insert data in an infinite loop).
+ * By default, this is 1 GB, which should be sufficient for most applications.
+ * In general, a maximum size prevents the database from growing indefinitely when something goes wrong
+ * (for example data is put in an infinite loop).
+ *
+ * This value can be changed, so increased or also decreased, each time when opening a store.
*/
public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {
if (maxSizeInKByte <= maxDataSizeInKByte) {
@@ -349,13 +354,17 @@ public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {
/**
* This API is experimental and may change or be removed in future releases.
*
- * Sets the maximum size the data stored in the database can grow to. Must be below {@link #maxSizeInKByte(long)}.
+ * Sets the maximum size the data stored in the database can grow to.
+ * When applying a transaction (e.g. putting an object) would exceed it a {@link DbMaxDataSizeExceededException}
+ * is thrown.
+ *
+ * Must be below {@link #maxSizeInKByte(long)}.
*
* Different from {@link #maxSizeInKByte(long)} this only counts bytes stored in objects, excluding system and
* metadata. However, it is more involved than database size tracking, e.g. it stores an internal counter.
* Only use this if a stricter, more accurate limit is required.
*
- * When the data limit is reached data can be removed to get below the limit again (assuming the database size limit
+ * When the data limit is reached, data can be removed to get below the limit again (assuming the database size limit
* is not also reached).
*/
@Experimental
@@ -455,7 +464,7 @@ public BoxStoreBuilder debugRelations() {
* {@link io.objectbox.exception.DbException} are thrown during query execution).
*
* @param queryAttempts number of attempts a query find operation will be executed before failing.
- * Recommended values are in the range of 2 to 5, e.g. a value of 3 as a starting point.
+ * Recommended values are in the range of 2 to 5, e.g. a value of 3 as a starting point.
*/
@Experimental
public BoxStoreBuilder queryAttempts(int queryAttempts) {
diff --git a/objectbox-java/src/main/java/io/objectbox/exception/DbFullException.java b/objectbox-java/src/main/java/io/objectbox/exception/DbFullException.java
index 5b0da063..2ac5b9a6 100644
--- a/objectbox-java/src/main/java/io/objectbox/exception/DbFullException.java
+++ b/objectbox-java/src/main/java/io/objectbox/exception/DbFullException.java
@@ -16,6 +16,10 @@
package io.objectbox.exception;
+/**
+ * Thrown when applying a transaction (e.g. putting an object) would exceed the
+ * {@link io.objectbox.BoxStoreBuilder#maxSizeInKByte(long) maxSizeInKByte} configured for the store.
+ */
public class DbFullException extends DbException {
public DbFullException(String message) {
super(message);
From e5f579d476f02b64ee2f556efeef4c148fba4b35 Mon Sep 17 00:00:00 2001
From: greenrobot Team
Date: Mon, 4 May 2020 15:15:00 +0200
Subject: [PATCH 019/352] Unchecked warnings: fix type params for
ToOneGetter/ToManyGetter (#59)
---
.../io/objectbox/internal/ToManyGetter.java | 4 ++--
.../io/objectbox/internal/ToOneGetter.java | 4 ++--
.../io/objectbox/relation/RelationInfo.java | 20 +++++++++----------
.../java/io/objectbox/relation/ToMany.java | 4 ++--
.../java/io/objectbox/relation/Customer_.java | 6 +++---
.../java/io/objectbox/relation/Order_.java | 2 +-
.../java/io/objectbox/tree/DataBranch_.java | 4 ++--
.../java/io/objectbox/tree/DataLeaf_.java | 4 ++--
.../java/io/objectbox/tree/MetaBranch_.java | 2 +-
.../java/io/objectbox/tree/MetaLeaf_.java | 2 +-
10 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/ToManyGetter.java b/objectbox-java/src/main/java/io/objectbox/internal/ToManyGetter.java
index 8eb29102..c9a7ad28 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/ToManyGetter.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/ToManyGetter.java
@@ -22,6 +22,6 @@
import io.objectbox.annotation.apihint.Internal;
@Internal
-public interface ToManyGetter extends Serializable {
- List getToMany(SOURCE object);
+public interface ToManyGetter extends Serializable {
+ List getToMany(SOURCE object);
}
diff --git a/objectbox-java/src/main/java/io/objectbox/internal/ToOneGetter.java b/objectbox-java/src/main/java/io/objectbox/internal/ToOneGetter.java
index 51c70e5c..90e2a68a 100644
--- a/objectbox-java/src/main/java/io/objectbox/internal/ToOneGetter.java
+++ b/objectbox-java/src/main/java/io/objectbox/internal/ToOneGetter.java
@@ -22,6 +22,6 @@
import io.objectbox.relation.ToOne;
@Internal
-public interface ToOneGetter extends Serializable {
- ToOne getToOne(SOURCE object);
+public interface ToOneGetter extends Serializable {
+ ToOne getToOne(SOURCE object);
}
diff --git a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
index a1f70592..ef492bf9 100644
--- a/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
+++ b/objectbox-java/src/main/java/io/objectbox/relation/RelationInfo.java
@@ -46,16 +46,16 @@ public class RelationInfo implements Serializable {
public final int targetRelationId;
/** Only set for ToOne relations */
- public final ToOneGetter toOneGetter;
+ public final ToOneGetter toOneGetter;
/** Only set for ToMany relations */
- public final ToManyGetter toManyGetter;
+ public final ToManyGetter toManyGetter;
/** For ToMany relations based on ToOne backlinks (null otherwise). */
- public final ToOneGetter backlinkToOneGetter;
+ public final ToOneGetter backlinkToOneGetter;
/** For ToMany relations based on ToMany backlinks (null otherwise). */
- public final ToManyGetter backlinkToManyGetter;
+ public final ToManyGetter backlinkToManyGetter;
/** For stand-alone to-many relations (0 otherwise). */
public final int relationId;
@@ -64,7 +64,7 @@ public class RelationInfo implements Serializable {
* ToOne
*/
public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, Property targetIdProperty,
- ToOneGetter toOneGetter) {
+ ToOneGetter toOneGetter) {
this.sourceInfo = sourceInfo;
this.targetInfo = targetInfo;
this.targetIdProperty = targetIdProperty;
@@ -79,8 +79,8 @@ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo
/**
* ToMany as a ToOne backlink
*/
- public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
- Property targetIdProperty, ToOneGetter backlinkToOneGetter) {
+ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
+ Property targetIdProperty, ToOneGetter backlinkToOneGetter) {
this.sourceInfo = sourceInfo;
this.targetInfo = targetInfo;
this.targetIdProperty = targetIdProperty;
@@ -95,8 +95,8 @@ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo
/**
* ToMany as a ToMany backlink
*/
- public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
- ToManyGetter backlinkToManyGetter, int targetRelationId) {
+ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
+ ToManyGetter backlinkToManyGetter, int targetRelationId) {
this.sourceInfo = sourceInfo;
this.targetInfo = targetInfo;
this.toManyGetter = toManyGetter;
@@ -111,7 +111,7 @@ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo
/**
* Stand-alone ToMany.
*/
- public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
+ public RelationInfo(EntityInfo sourceInfo, EntityInfo targetInfo, ToManyGetter toManyGetter,
int relationId) {
this.sourceInfo = sourceInfo;
this.targetInfo = targetInfo;
diff --git a/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java b/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
index ac3f43de..b387c0df 100644
--- a/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
+++ b/objectbox-java/src/main/java/io/objectbox/relation/ToMany.java
@@ -696,7 +696,7 @@ public boolean internalCheckApplyToDbRequired() {
private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter idGetter,
@Nullable Map setAdded, @Nullable Map setRemoved) {
- ToManyGetter backlinkToManyGetter = relationInfo.backlinkToManyGetter;
+ ToManyGetter backlinkToManyGetter = relationInfo.backlinkToManyGetter;
synchronized (this) {
if (setAdded != null && !setAdded.isEmpty()) {
@@ -740,7 +740,7 @@ private boolean prepareToManyBacklinkEntitiesForDb(long entityId, IdGetter idGetter,
@Nullable Map setAdded, @Nullable Map setRemoved) {
- ToOneGetter backlinkToOneGetter = relationInfo.backlinkToOneGetter;
+ ToOneGetter backlinkToOneGetter = relationInfo.backlinkToOneGetter;
synchronized (this) {
if (setAdded != null && !setAdded.isEmpty()) {
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
index 02a45bd3..1d303763 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Customer_.java
@@ -109,12 +109,12 @@ public long getId(Customer object) {
}
public static final RelationInfo orders =
- new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
+ new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
@Override
public List getToMany(Customer customer) {
return customer.getOrders();
}
- }, Order_.customerId, new ToOneGetter() {
+ }, Order_.customerId, new ToOneGetter() {
@Override
public ToOne getToOne(Order order) {
return order.getCustomer();
@@ -122,7 +122,7 @@ public ToOne getToOne(Order order) {
});
public static final RelationInfo ordersStandalone =
- new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
+ new RelationInfo<>(Customer_.__INSTANCE, Order_.__INSTANCE, new ToManyGetter() {
@Override
public List getToMany(Customer customer) {
return customer.getOrders();
diff --git a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
index e2742d77..1165b499 100644
--- a/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
+++ b/tests/objectbox-java-test/src/main/java/io/objectbox/relation/Order_.java
@@ -110,7 +110,7 @@ public long getId(Order object) {
}
}
- public static final RelationInfo customer = new RelationInfo<>(Order_.__INSTANCE, Customer_.__INSTANCE, customerId, new ToOneGetter() {
+ public static final RelationInfo customer = new RelationInfo<>(Order_.__INSTANCE, Customer_.__INSTANCE, customerId, new ToOneGetter() {
@Override
public ToOne getToOne(Order object) {
return object.getCustomer();
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataBranch_.java b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataBranch_.java
index 7a31f3ca..26a0b8b4 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataBranch_.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataBranch_.java
@@ -106,7 +106,7 @@ public long getId(DataBranch object) {
/** To-one relation "parent" to target entity "DataBranch". */
public static final RelationInfo parent =
- new RelationInfo<>(DataBranch_.__INSTANCE, DataBranch_.__INSTANCE, parentId, new ToOneGetter() {
+ new RelationInfo<>(DataBranch_.__INSTANCE, DataBranch_.__INSTANCE, parentId, new ToOneGetter() {
@Override
public ToOne getToOne(DataBranch entity) {
return entity.parent;
@@ -115,7 +115,7 @@ public ToOne getToOne(DataBranch entity) {
/** To-one relation "metaBranch" to target entity "MetaBranch". */
public static final RelationInfo metaBranch =
- new RelationInfo<>(DataBranch_.__INSTANCE, MetaBranch_.__INSTANCE, metaBranchId, new ToOneGetter() {
+ new RelationInfo<>(DataBranch_.__INSTANCE, MetaBranch_.__INSTANCE, metaBranchId, new ToOneGetter() {
@Override
public ToOne getToOne(DataBranch entity) {
return entity.metaBranch;
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataLeaf_.java b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataLeaf_.java
index 3b433789..a5068560 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataLeaf_.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/DataLeaf_.java
@@ -118,7 +118,7 @@ public long getId(DataLeaf object) {
/** To-one relation "dataBranch" to target entity "DataBranch". */
public static final RelationInfo dataBranch =
- new RelationInfo<>(DataLeaf_.__INSTANCE, io.objectbox.tree.DataBranch_.__INSTANCE, dataBranchId, new ToOneGetter() {
+ new RelationInfo<>(DataLeaf_.__INSTANCE, io.objectbox.tree.DataBranch_.__INSTANCE, dataBranchId, new ToOneGetter() {
@Override
public ToOne getToOne(DataLeaf entity) {
return entity.dataBranch;
@@ -127,7 +127,7 @@ public ToOne getToOne(DataLeaf entity) {
/** To-one relation "metaLeaf" to target entity "MetaLeaf". */
public static final RelationInfo metaLeaf =
- new RelationInfo<>(DataLeaf_.__INSTANCE, io.objectbox.tree.MetaLeaf_.__INSTANCE, metaLeafId, new ToOneGetter() {
+ new RelationInfo<>(DataLeaf_.__INSTANCE, io.objectbox.tree.MetaLeaf_.__INSTANCE, metaLeafId, new ToOneGetter() {
@Override
public ToOne getToOne(DataLeaf entity) {
return entity.metaLeaf;
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaBranch_.java b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaBranch_.java
index fba17354..cfbe6893 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaBranch_.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaBranch_.java
@@ -106,7 +106,7 @@ public long getId(MetaBranch object) {
/** To-one relation "parent" to target entity "MetaBranch". */
public static final RelationInfo parent =
- new RelationInfo<>(MetaBranch_.__INSTANCE, MetaBranch_.__INSTANCE, parentId, new ToOneGetter() {
+ new RelationInfo<>(MetaBranch_.__INSTANCE, MetaBranch_.__INSTANCE, parentId, new ToOneGetter() {
@Override
public ToOne getToOne(MetaBranch entity) {
return entity.parent;
diff --git a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaLeaf_.java b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaLeaf_.java
index 5213cb24..0610fee8 100644
--- a/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaLeaf_.java
+++ b/tests/objectbox-java-test/src/test/java/io/objectbox/tree/MetaLeaf_.java
@@ -129,7 +129,7 @@ public long getId(MetaLeaf object) {
/** To-one relation "branch" to target entity "MetaBranch". */
public static final RelationInfo branch =
- new RelationInfo<>(MetaLeaf_.__INSTANCE, MetaBranch_.__INSTANCE, branchId, new ToOneGetter() {
+ new RelationInfo<>(MetaLeaf_.__INSTANCE, MetaBranch_.__INSTANCE, branchId, new ToOneGetter() {
@Override
public ToOne