Skip to content

Commit 11f9a60

Browse files
committed
multiple refactorings: Cursor creation via factory, added RelationInfo, extended Properties class to be single source for entity info
1 parent 52324ba commit 11f9a60

28 files changed

Lines changed: 509 additions & 191 deletions

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class Box<T> {
4242
Box(BoxStore store, Class<T> entityClass) {
4343
this.store = store;
4444
this.entityClass = entityClass;
45-
idGetter = store.getProperties(entityClass).getIdGetter();
45+
idGetter = store.getEntityInfo(entityClass).getIdGetter();
4646
debugTx = store.debugTx;
4747
}
4848

@@ -483,7 +483,7 @@ public void removeAll() {
483483
* Returns a builder to create queries for Object matching supplied criteria.
484484
*/
485485
public QueryBuilder<T> query() {
486-
return new QueryBuilder<>(this, store.internalHandle(), store.getEntityName(entityClass));
486+
return new QueryBuilder<>(this, store.internalHandle(), store.getDbName(entityClass));
487487
}
488488

489489
public BoxStore getStore() {

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

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828

2929
import javax.annotation.concurrent.ThreadSafe;
3030

31-
import io.objectbox.BoxStoreBuilder.EntityClasses;
3231
import io.objectbox.annotation.apihint.Beta;
3332
import io.objectbox.annotation.apihint.Internal;
3433
import io.objectbox.converter.PropertyConverter;
@@ -171,8 +170,7 @@ public static String getVersion() {
171170

172171
private final File directory;
173172
private final long handle;
174-
private final Map<Class, String> entityNameByClass = new HashMap<>();
175-
private final Map<Class, Class<Cursor>> entityCursorClassByClass = new HashMap<>();
173+
private final Map<Class, String> dbNameByClass = new HashMap<>();
176174
private final Map<Class, Integer> entityTypeIdByClass = new HashMap<>();
177175
private final Map<Class, Properties> propertiesByClass = new HashMap<>();
178176
private final LongHashMap<Class> classByEntityTypeId = new LongHashMap<>();
@@ -206,15 +204,14 @@ public static String getVersion() {
206204
handle = nativeCreate(directory.getAbsolutePath(), builder.maxSizeInKByte, builder.model);
207205
debugTx = builder.debugTransactions;
208206

209-
for (EntityClasses entity : builder.entityClasses) {
207+
for (Properties entityInfo : builder.entityInfoList) {
210208
try {
211-
entityNameByClass.put(entity.entityClass, entity.entityName);
212-
entityCursorClassByClass.put(entity.entityClass, entity.cursorClass);
213-
int entityId = nativeRegisterEntityClass(handle, entity.entityName, entity.entityClass);
214-
entityTypeIdByClass.put(entity.entityClass, entityId);
215-
classByEntityTypeId.put(entityId, entity.entityClass);
216-
propertiesByClass.put(entity.entityClass, entity.properties);
217-
for (Property property : entity.properties.getAllProperties()) {
209+
dbNameByClass.put(entityInfo.getEntityClass(), entityInfo.getDbName());
210+
int entityId = nativeRegisterEntityClass(handle, entityInfo.getDbName(), entityInfo.getEntityClass());
211+
entityTypeIdByClass.put(entityInfo.getEntityClass(), entityId);
212+
classByEntityTypeId.put(entityId, entityInfo.getEntityClass());
213+
propertiesByClass.put(entityInfo.getEntityClass(), entityInfo);
214+
for (Property property : entityInfo.getAllProperties()) {
218215
if (property.customType != null) {
219216
if (property.converterClass == null) {
220217
throw new RuntimeException("No converter class for custom type of " + property);
@@ -224,7 +221,7 @@ public static String getVersion() {
224221
}
225222
}
226223
} catch (RuntimeException e) {
227-
throw new RuntimeException("Could not setup up entity " + entity.entityClass, e);
224+
throw new RuntimeException("Could not setup up entity " + entityInfo.getEntityClass(), e);
228225
}
229226
}
230227
int size = classByEntityTypeId.size();
@@ -249,8 +246,8 @@ private void checkOpen() {
249246
}
250247
}
251248

252-
String getEntityName(Class entityClass) {
253-
return entityNameByClass.get(entityClass);
249+
String getDbName(Class entityClass) {
250+
return dbNameByClass.get(entityClass);
254251
}
255252

256253
Integer getEntityTypeId(Class entityClass) {
@@ -267,7 +264,7 @@ public int getEntityTypeIdOrThrow(Class entityClass) {
267264
}
268265

269266
public Collection<Class> getAllEntityClasses() {
270-
return entityNameByClass.keySet();
267+
return dbNameByClass.keySet();
271268
}
272269

273270
@Internal
@@ -284,12 +281,8 @@ Class getEntityClassOrThrow(int entityTypeId) {
284281
return clazz;
285282
}
286283

287-
<T> Class<Cursor<T>> getEntityCursorClass(Class<T> entityClass) {
288-
return (Class) entityCursorClassByClass.get(entityClass);
289-
}
290-
291284
@Internal
292-
Properties getProperties(Class entityClass) {
285+
Properties getEntityInfo(Class entityClass) {
293286
return propertiesByClass.get(entityClass);
294287
}
295288

@@ -412,7 +405,7 @@ void txCommitted(Transaction tx, int[] entityTypeIdsAffected) {
412405
public <T> Box<T> boxFor(Class<T> entityClass) {
413406
Box box = boxes.get(entityClass);
414407
if (box == null) {
415-
if (!entityNameByClass.containsKey(entityClass)) {
408+
if (!dbNameByClass.containsKey(entityClass)) {
416409
throw new IllegalArgumentException(entityClass +
417410
" is not a known entity. Please add it and trigger generation again.");
418411
}

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

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,6 @@ public class BoxStoreBuilder {
1212

1313
public static final String DEFAULT_NAME = "objectbox";
1414

15-
static class EntityClasses<T> {
16-
final String entityName;
17-
final Class<T> entityClass;
18-
final Class<? extends Cursor<T>> cursorClass;
19-
final Properties properties;
20-
21-
EntityClasses(String entityName, Class<T> entityClass, Class<? extends Cursor<T>> cursorClass,
22-
Properties properties) {
23-
this.entityName = entityName;
24-
this.entityClass = entityClass;
25-
this.cursorClass = cursorClass;
26-
this.properties = properties;
27-
}
28-
}
29-
3015
final byte[] model;
3116

3217
/** BoxStore uses this */
@@ -47,7 +32,7 @@ static class EntityClasses<T> {
4732

4833
boolean debugTransactions;
4934

50-
final List<EntityClasses> entityClasses = new ArrayList<>();
35+
final List<Properties> entityInfoList = new ArrayList<>();
5136

5237
public BoxStoreBuilder(byte[] model) {
5338
this.model = model;
@@ -122,17 +107,15 @@ public BoxStoreBuilder androidContext(Object context) {
122107
}
123108

124109
@Internal
125-
public <T> void entity(String entityName, Class<T> entityClass, Class<? extends Cursor<T>> cursorClass,
126-
Properties properties) {
127-
EntityClasses<T> info = new EntityClasses<>(entityName, entityClass, cursorClass, properties);
128-
entityClasses.add(info);
110+
public <T> void entity(Properties properties) {
111+
entityInfoList.add(properties);
129112
}
130113

131114
// Not sure this will ever be implements
132115
BoxStoreBuilder modelUpdate(ModelUpdate modelUpdate) {
133116
throw new UnsupportedOperationException("Not yet implemented");
134-
// this.modelUpdate = modelUpdate;
135-
// return this;
117+
// this.modelUpdate = modelUpdate;
118+
// return this;
136119
}
137120

138121
public BoxStoreBuilder maxSizeInKByte(long maxSizeInKByte) {

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

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,20 +96,20 @@ protected static native long collect004000(long cursor, long keyIfComplete, int
9696
protected Transaction tx;
9797
protected final long cursor;
9898
protected final Properties properties;
99-
100-
protected BoxStore boxStoreForEntities;
99+
protected final BoxStore boxStoreForEntities;
101100

102101
protected boolean closed;
103102

104103
private final Throwable creationThrowable;
105104

106-
protected Cursor(Transaction tx, long cursor, Properties properties) {
105+
protected Cursor(Transaction tx, long cursor, Properties properties, BoxStore boxStore) {
107106
if (tx == null) {
108107
throw new IllegalArgumentException("Transaction is null");
109108
}
110109
this.tx = tx;
111110
this.cursor = cursor;
112111
this.properties = properties;
112+
this.boxStoreForEntities = boxStore;
113113

114114
Property[] allProperties = properties.getAllProperties();
115115
for (Property property : allProperties) {
@@ -119,6 +119,8 @@ protected Cursor(Transaction tx, long cursor, Properties properties) {
119119
}
120120
}
121121
creationThrowable = WARN_FINALIZER ? new Throwable() : null;
122+
123+
nativeSetBoxStoreForEntities(cursor, boxStore);
122124
}
123125

124126
@Override
@@ -251,11 +253,6 @@ List<T> getBacklinkEntities(int entityId, Property relationIdProperty, long key)
251253
}
252254
}
253255

254-
public void setBoxStoreForEntities(BoxStore boxStore) {
255-
boxStoreForEntities = boxStore;
256-
nativeSetBoxStoreForEntities(cursor, boxStore);
257-
}
258-
259256
@Override
260257
public String toString() {
261258
return "Cursor " + Long.toString(cursor, 16) + (isClosed() ? "(closed)" : "");
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
package io.objectbox;
22

33
import io.objectbox.annotation.apihint.Internal;
4+
import io.objectbox.internal.CursorFactory;
45
import io.objectbox.internal.IdGetter;
56

67
@Internal
7-
public interface Properties {
8+
// TODO rename to EntityInfo (?)
9+
public interface Properties<T> {
10+
String getEntityName();
11+
String getDbName();
12+
13+
Class<T> getEntityClass();
14+
815
Property[] getAllProperties();
916
Property getIdProperty();
10-
String getDbName();
1117

12-
@Internal
13-
<T> IdGetter<T> getIdGetter();
18+
IdGetter<T> getIdGetter();
19+
CursorFactory<T> getCursorFactory();
1420
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public class Property {
4343
/** Type, which is converted to a type supported by the DB. */
4444
public final Class customType;
4545

46+
// TODO verified state should be per DB -> move to BoxStore/Box.
47+
// Also, this should make the Property class truly @Immutable.
4648
private boolean idVerified;
4749

4850
public Property(int ordinal, int id, Class<?> type, String name, boolean primaryKey, String dbName) {

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

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,17 @@
11
package io.objectbox;
22

33
import java.io.Closeable;
4-
import java.lang.reflect.Constructor;
5-
import java.util.Map;
6-
import java.util.concurrent.ConcurrentHashMap;
74

85
import javax.annotation.concurrent.NotThreadSafe;
96

107
import io.objectbox.annotation.apihint.Internal;
11-
import io.objectbox.exception.DbException;
8+
import io.objectbox.internal.CursorFactory;
129

1310
@Internal
1411
@NotThreadSafe
1512
public class Transaction implements Closeable {
1613
static final boolean WARN_FINALIZER = false;
1714

18-
static final Map<Class, Constructor> cursorConstructorCache = new ConcurrentHashMap<>();
19-
2015
private final long transaction;
2116
private final BoxStore store;
2217
private final boolean readOnly;
@@ -132,27 +127,10 @@ public KeyValueCursor createKeyValueCursor() {
132127

133128
public <T> Cursor<T> createCursor(Class<T> entityClass) {
134129
checkOpen();
135-
Class<Cursor<T>> cursorClass = store.getEntityCursorClass(entityClass);
136-
String entityName = store.getEntityName(entityClass);
137-
if (entityClass == null || cursorClass == null) {
138-
throw new DbException("No entity info registered in store for " + entityClass);
139-
}
140-
try {
141-
// TODO use CursorFactory instead
142-
Constructor<Cursor<T>> cursorConstructor = cursorConstructorCache.get(cursorClass);
143-
if (cursorConstructor == null) {
144-
cursorConstructor = cursorClass.getConstructor(Transaction.class, long.class);
145-
cursorConstructorCache.put(cursorClass, cursorConstructor);
146-
}
147-
long cursorHandle = nativeCreateCursor(transaction, entityName, entityClass);
148-
Cursor<T> cursor = cursorConstructor.newInstance(this, cursorHandle);
149-
150-
// TODO make this part of constructor too?
151-
cursor.setBoxStoreForEntities(store);
152-
return cursor;
153-
} catch (Exception e) {
154-
throw new RuntimeException("Could not create cursor", e);
155-
}
130+
Properties entityInfo = store.getEntityInfo(entityClass);
131+
CursorFactory<T> factory = entityInfo.getCursorFactory();
132+
long cursorHandle = nativeCreateCursor(transaction, entityInfo.getDbName(), entityClass);
133+
return factory.createCursor(this, cursorHandle, store);
156134
}
157135

158136
public BoxStore getStore() {
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package io.objectbox.internal;
22

3+
import javax.annotation.Nullable;
4+
5+
import io.objectbox.BoxStore;
36
import io.objectbox.Cursor;
47
import io.objectbox.Transaction;
58
import io.objectbox.annotation.apihint.Internal;
69

710
@Internal
8-
// TODO use me
911
public interface CursorFactory<T> {
10-
Cursor<T> createCursor(Transaction tx, long cursorHandle);
12+
Cursor<T> createCursor(Transaction tx, long cursorHandle, @Nullable BoxStore boxStore);
1113
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package io.objectbox.relation;
2+
3+
import javax.annotation.Nullable;
4+
5+
import io.objectbox.Property;
6+
import io.objectbox.annotation.apihint.Internal;
7+
import io.objectbox.internal.IdGetter;
8+
9+
@Internal
10+
public class RelationInfo<TARGET> {
11+
public final Class sourceClass;
12+
public final @Nullable Property targetIdProperty;
13+
public final Class<TARGET> targetClass;
14+
public final IdGetter<TARGET> targetIdGetter;
15+
16+
public RelationInfo(Class sourceClass, @Nullable Property targetIdProperty, Class<TARGET> targetClass,
17+
IdGetter<TARGET> targetIdGetter) {
18+
this.sourceClass = sourceClass;
19+
this.targetIdProperty = targetIdProperty;
20+
this.targetClass = targetClass;
21+
this.targetIdGetter = targetIdGetter;
22+
}
23+
}
24+

tests/objectbox-java-test/src/main/java/io/objectbox/AbstractObjectBoxTest.java

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import io.objectbox.ModelBuilder.EntityBuilder;
1515
import io.objectbox.ModelBuilder.PropertyBuilder;
16+
import io.objectbox.internal.CursorFactory;
1617
import io.objectbox.internal.IdGetter;
1718
import io.objectbox.model.PropertyFlags;
1819
import io.objectbox.model.PropertyType;
@@ -53,39 +54,14 @@ protected BoxStore createBoxStore(boolean withIndex) {
5354

5455
protected BoxStoreBuilder createBoxStoreBuilderWithTwoEntities(boolean withIndex) {
5556
BoxStoreBuilder builder = new BoxStoreBuilder(createTestModelWithTwoEntities(withIndex)).directory(boxStoreDir);
56-
builder.entity("TestEntity", TestEntity.class, TestEntityCursor.class, new TestEntity_());
57-
builder.entity("TestEntityMinimal", TestEntityMinimal.class, TestEntityMinimalCursor.class, new Properties() {
58-
@Override
59-
public Property[] getAllProperties() {
60-
return new Property[0];
61-
}
62-
63-
@Override
64-
public Property getIdProperty() {
65-
return null;
66-
}
67-
68-
@Override
69-
public String getDbName() {
70-
return null;
71-
}
72-
73-
@Override
74-
public IdGetter<TestEntityMinimal> getIdGetter() {
75-
return new IdGetter<TestEntityMinimal>() {
76-
@Override
77-
public long getId(TestEntityMinimal object) {
78-
return object.getId();
79-
}
80-
};
81-
}
82-
});
57+
builder.entity(new TestEntity_());
58+
builder.entity(new TestEntityMinimal_());
8359
return builder;
8460
}
8561

8662
protected BoxStoreBuilder createBoxStoreBuilder(boolean withIndex) {
8763
BoxStoreBuilder builder = new BoxStoreBuilder(createTestModel(withIndex)).directory(boxStoreDir);
88-
builder.entity("TestEntity", TestEntity.class, TestEntityCursor.class, new TestEntity_());
64+
builder.entity(new TestEntity_());
8965
return builder;
9066
}
9167

0 commit comments

Comments
 (0)