How to register a custom property type in xodus `PersistentEntityStore`
I am working with xodus database and I want to store java.time.Instant
as a property of my model object ( Diary
), so I have implemented InstantBinding
.
Next, in the repository object that I created to work with my objects Diary
, I registered InstantBindig
in the save and load methods of the repository because it PersistentEntityStore.registerCustomPropertyType(@NotNull final StoreTransaction txn, @NotNull final Class<? extends Comparable> clazz,@NotNull final ComparableBinding binding);
needs to be logged in StoreTransaction txn
. and then when i use the repository i get this exception:
Exception in thread "JavaFX Application Thread" jetbrains.exodus.entitystore.EntityStoreException: Already registered property type id 9
at jetbrains.exodus.entitystore.tables.PropertyTypes.registerCustomPropertyType(PropertyTypes.java:77)
at jetbrains.exodus.entitystore.PersistentEntityStoreImpl.registerCustomPropertyType(PersistentEntityStoreImpl.java:520)
at io.github.mojtab23.diaries.DiaryRepository.lambda$saveDiary$0(DiaryRepository.java:35)
at jetbrains.exodus.entitystore.PersistentEntityStoreImpl.executeInTransaction(PersistentEntityStoreImpl.java:529)
at io.github.mojtab23.diaries.DiaryRepository.saveDiary(DiaryRepository.java:34)
at io.github.mojtab23.diaries.DiariesView.saveChanges(DiariesView.java:222)
at io.github.mojtab23.diaries.DiariesView.lambda$buildDiaryEditor$6(DiariesView.java:203)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Node.fireEvent(Node.java:8413)
at javafx.scene.control.Button.fire(Button.java:185)
at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3757)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:381)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:417)
at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
at com.sun.glass.ui.View.notifyMouse(View.java:937)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$148(WinApplication.java:191)
at java.lang.Thread.run(Thread.java:745)
So what is the correct way to register a custom property type for xodus?
here are my classes:
A diary
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import jetbrains.exodus.entitystore.EntityId;
public class Diary implements Cloneable {
private final ObjectProperty<Instant> timestamp;
private final StringProperty text;
private EntityId id;
public Diary() {
this.text = new SimpleStringProperty();
timestamp = new SimpleObjectProperty<>(Instant.now());
}
public Diary(String text, Instant time) {
this.text = new SimpleStringProperty(text);
timestamp = new SimpleObjectProperty<>(time);
}
public Diary(SimpleObjectProperty<Instant> timestamp, StringProperty text, EntityId id) {
this.timestamp = timestamp;
this.text = text;
this.id = id;
}
public EntityId getId() {
return id;
}
public void setId(EntityId id) {
this.id = id;
}
public Instant getTimestamp() {
return timestamp.get();
}
public void setTimestamp(Instant timestamp) {
this.timestamp.set(timestamp);
}
public ObjectProperty<Instant> timestampProperty() {
return timestamp;
}
public String getText() {
return text.get();
}
public void setText(String text) {
this.text.set(text);
}
public StringProperty textProperty() {
return text;
}
@Override
public String toString() {
return "Diary{" +
"id=" + id +
", timestamp=" + timestamp +
", text=" + text +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
DiaryRepository:
import io.github.mojtab23.diaries.model.diary.Diary;
import jetbrains.exodus.entitystore.*;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;
import javax.annotation.PreDestroy;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@Repository
public class DiaryRepository {
private static final Logger LOGGER = LoggerFactory.getLogger(DiaryRepository.class);
private final PersistentEntityStore entityStore;
private final String entityType = "Diary";
public DiaryRepository() {
entityStore = PersistentEntityStores.newInstance(".DiariesAppData");
}
public void saveDiary(final Diary diary) {
entityStore.executeInTransaction((StoreTransaction txn) -> {
entityStore.registerCustomPropertyType(txn, Instant.class, InstantBinding.BINDING);
diaryToEntity(diary, txn);
});
}
public Entity diaryToEntity(final Diary diary, final StoreTransaction txn) {
final Entity diaryEntity = txn.newEntity(entityType);
diaryEntity.setProperty("text", diary.getText());
diaryEntity.setProperty("timestamp", diary.getTimestamp());
return diaryEntity;
}
public Diary entityToDiary(final Entity entity, final StoreTransaction txn) {
final @Nullable String text = (String) entity.getProperty("text");
final @Nullable Instant timestamp = (Instant) entity.getProperty("timestamp");
if (text != null) {
if (timestamp != null) {
return new Diary(text, timestamp);
} else
return new Diary(text, Instant.MIN);
}
return null;
}
public List<Diary> readAllDiaries() {
return entityStore.computeInReadonlyTransaction(txn -> {
entityStore.registerCustomPropertyType(txn, Instant.class, InstantBinding.BINDING);
final EntityIterable allDiaries = txn.getAll(entityType);
final List<Diary> diaryList = new ArrayList<>();
allDiaries.forEach(entity -> {
final Diary e = entityToDiary(entity, txn);
if (e != null) {
diaryList.add(e);
}
});
LOGGER.warn("Number of Diaries: " + diaryList.size());
return diaryList;
});
}
public void deleteAll() {
entityStore.executeInTransaction(txn -> {
txn.getAll(entityType).forEach(entity ->
{
if (!entity.delete()) {
LOGGER.warn("cant delete {}", entityToDiary(entity, txn));
}
});
});
}
@PreDestroy
public void atEnd() {
entityStore.close();
}
}
InstantBinding:
import jetbrains.exodus.ArrayByteIterable;
import jetbrains.exodus.ByteIterable;
import jetbrains.exodus.bindings.BindingUtils;
import jetbrains.exodus.bindings.ComparableBinding;
import jetbrains.exodus.util.LightOutputStream;
import org.jetbrains.annotations.NotNull;
import java.io.ByteArrayInputStream;
import java.time.Instant;
public class InstantBinding extends ComparableBinding {
public static final InstantBinding BINDING = new InstantBinding();
public static Instant entryToInstant(@NotNull final ByteIterable entry) {
return (Instant) BINDING.entryToObject(entry);
}
public static ArrayByteIterable instantToEntry(final Instant object) {
return BINDING.objectToEntry(object);
}
@Override
public Comparable readObject(@NotNull ByteArrayInputStream stream) {
final long l = BindingUtils.readLong(stream);
final int i = BindingUtils.readInt(stream);
return Instant.ofEpochSecond(l, i);
}
@Override
public void writeObject(@NotNull LightOutputStream output, @NotNull Comparable object) {
final Instant instant = (Instant) object;
output.writeUnsignedLong(instant.getEpochSecond() ^ 0x8000000000000000L);
output.writeUnsignedInt(instant.getNano() ^ 0x80000000);
}
}
source to share
You seem to be experiencing this error . It has already been fixed, the fix will be available in version 1.0.6. There are currently two ways:
- Call the call
PersistentEntityStore.registerCustomPropertyType()
with a try-catch block, catch it,EntityStoreException
and ignore it. When the next version (1.0.6) is available, make a project based on it and remove the try-catch block. - Set your project based on the version
1.0.6-SNAPSHOT
published in the Sonartype snapshot repository .
source to share