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);

    }

}

      

+3


source to share


1 answer


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 .
+1


source







All Articles