Search code examples
javaapache-commonsmicrostream

Java Microstream - ImmutablePair causing PersistenceExceptionTypeNotPersistable


Apache ImmutablePair, (org.apache.commons.lang3.tuple.ImmutablePair) causing PersistenceExceptionTypeNotPersistable when storing Java Object graph.

How should I solve this? If with a typeHandler, is there an example?

Caused by: one.microstream.persistence.exceptions.PersistenceExceptionTypeNotPersistable: Type not persistable: "class org.apache.commons.lang3.tuple.ImmutablePair".
    at one.microstream.persistence.binary.internal.BinaryHandlerUnpersistable.guaranteeSpecificInstanceViablity(BinaryHandlerUnpersistable.java:66)
    at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.ensureTypeHandler(PersistenceTypeHandlerManager.java:336)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.registerGuaranteed(BinaryStorer.java:557)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.registerLazyOptional(BinaryStorer.java:572)
    at one.microstream.persistence.types.PersistenceObjectManager$Default.ensureObjectId(PersistenceObjectManager.java:182)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.register(BinaryStorer.java:591)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.apply(BinaryStorer.java:298)
    at one.microstream.persistence.binary.types.Binary.storeIterableContentAsList(Binary.java:1698)
    at one.microstream.persistence.binary.types.Binary.storeIterableAsList(Binary.java:668)
    at one.microstream.persistence.binary.internal.AbstractBinaryHandlerCustomIterableSimpleListElements.store(AbstractBinaryHandlerCustomIterableSimpleListElements.java:64)
    at one.microstream.persistence.binary.internal.AbstractBinaryHandlerCustomIterableSimpleListElements.store(AbstractBinaryHandlerCustomIterableSimpleListElements.java:1)
    at one.microstream.persistence.binary.internal.AbstractBinaryHandlerCustom.store(AbstractBinaryHandlerCustom.java:1)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.storeItem(BinaryStorer.java:414)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.storeGraph(BinaryStorer.java:403)
    at one.microstream.persistence.binary.types.BinaryStorer$Default.store(BinaryStorer.java:421)
    at one.microstream.persistence.types.PersistenceManager$Default.store(PersistenceManager.java:274)
    at one.microstream.storage.types.StorageConnection.store(StorageConnection.java:306)
    at one.microstream.cache.CacheStore$Default.write(CacheStore.java:112)

Solution

  • Below is the answer per shared by microstream directly, and I can confirm this works perfectly.

    Hello,

    If a class is considered as unpersitable it is possible to provide a custom type handler implementation for such classes. In your case a custom type handler may look like:

    import org.apache.commons.lang3.tuple.ImmutablePair;
    
    import one.microstream.persistence.binary.internal.CustomBinaryHandler;
    import one.microstream.persistence.binary.types.Binary;
    import one.microstream.persistence.binary.types.BinaryField;
    import one.microstream.persistence.types.PersistenceLoadHandler;
    import one.microstream.reflect.XReflect;
    
    public class ImmutablePairTypeHandler extends CustomBinaryHandler<ImmutablePair<?, ?>>
    {
        @SuppressWarnings({"unchecked", "rawtypes"})
        private static Class<ImmutablePair<?, ?>> handledType()
        {
            return (Class)ImmutablePair.class; // to get ".class" to work
        }
    
        //the fields to be persisted
        BinaryField<ImmutablePair<?, ?>> left = Field(Object.class, ImmutablePair::getLeft);
        BinaryField<ImmutablePair<?, ?>> right = Field(Object.class, ImmutablePair::getRight);
        
        public ImmutablePairTypeHandler()
        {
            super(handledType());
        }
        
        @Override
        public ImmutablePair<?, ?> create(final Binary data, final PersistenceLoadHandler handler)
        {
            //create a empty instance, don't use nullPair() as it is a static final
            return ImmutablePair.of(null, null);
        }
        
        @Override
        public void initializeState(final Binary data, final ImmutablePair<?, ?> instance, final PersistenceLoadHandler handler)
        {
            //get the referenced Objects
            final Object left = this.left.readReference(data, handler);
            final Object right = this.right.readReference(data, handler);
                
            //as the pair is immutable we can't set the pairs fields directly
            final ImmutablePair<?,?> pair = ImmutablePair.of(left, right);
            XReflect.copyFields(pair, instance);
        }   
    }
    

    To enable this handler just register it:

    final EmbeddedStorageFoundation<?> foundation = EmbeddedStorage.Foundation(workdir);
    foundation.registerTypeHandler(new ImmutablePairTypeHandler());
    
    final EmbeddedStorageManager storage = foundation.start();