Search code examples
javasyntheticmicrostream

Java Microstream - Synthetic classes - PersistenceExceptionTypeNotPersistable


Using Microstream getting the below exception. Being caused by a class with a reference to a static inner class. How do I resolve this issue?

The exception states the following, but the documentation doesn't explain how to implement a PersistenceTypeResolver

Details: Synthetic classes ($1 etc.) are not reliably persistence since a simple reordering of source code elements would change the name identity of a class. For a type system that has to rely upon resolving types by their identifying name, this would silently cause a potentially fatal error. If handling synthetic classes (e.g. anonymous inner classes) is absolutely necessary, a custom one.microstream.persistence.types.PersistenceTypeResolver can be used to remove the exception and assume complete responsibility for correctly handling synthetic class names. at one.microstream.persistence.types.Persistence.derivePersistentTypeName(Persistence.java:1083)

    public static final AbstractAccompanyingPassenger DUMMY = new AbstractAccompanyingPassenger(MetaDataAccompanyingType.DUMMY) {
        @Override
        public AbstractAccompanyingPassenger clone() {
            return DUMMY;
        }};
Caused by: one.microstream.persistence.exceptions.PersistenceExceptionTypeNotPersistable: Type not persistable: "class net.atpco.metadata.summary.accompanied.MetaDataAccompanying$1". Details: Synthetic classes ($1 etc.) are not reliably persistence since a simple reordering of source code elements would change the name identity of a class. For a type system that has to rely upon resolving types by their identifying name, this would silently cause a potentially fatal error. If handling synthetic classes (e.g. anonymous inner classes) is absolutely necessary, a custom one.microstream.persistence.types.PersistenceTypeResolver can be used to remove the exception and assume  complete responsibility for correctly handling synthetic class names.
    at one.microstream.persistence.types.Persistence.derivePersistentTypeName(Persistence.java:1083)
    at one.microstream.persistence.types.PersistenceTypeResolver.deriveTypeName(PersistenceTypeResolver.java:17)
    at one.microstream.persistence.types.PersistenceTypeHandlerCreator$Abstract.deriveTypeName(PersistenceTypeHandlerCreator.java:73)
    at one.microstream.persistence.binary.types.BinaryTypeHandlerCreator$Default.internalCreateTypeHandlerGeneric(BinaryTypeHandlerCreator.java:238)
    at one.microstream.persistence.types.PersistenceTypeHandlerCreator$Abstract.createTypeHandlerGeneric(PersistenceTypeHandlerCreator.java:168)
    at one.microstream.persistence.types.PersistenceTypeHandlerEnsurer$Default.ensureTypeHandler(PersistenceTypeHandlerEnsurer.java:199)
    at one.microstream.persistence.internal.PersistenceTypeHandlerProviderCreating.ensureTypeHandler(PersistenceTypeHandlerProviderCreating.java:170)
    at one.microstream.persistence.internal.PersistenceTypeHandlerProviderCreating.provideTypeHandler(PersistenceTypeHandlerProviderCreating.java:78)
    at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.internalEnsureTypeHandler(PersistenceTypeHandlerManager.java:587)
    at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.ensureTypeHandler(PersistenceTypeHandlerManager.java:357)
    at one.microstream.persistence.types.PersistenceTypeHandlerManager$Default.ensureTypeHandler(PersistenceTypeHandlerManager.java:333)
    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.BinaryValueFunctions$9.storeValueFromMemory(BinaryValueFunctions.java:147)
    at one.microstream.persistence.binary.types.Binary.storeFixedSize(Binary.java:1149)
    at one.microstream.persistence.binary.internal.AbstractBinaryHandlerReflective.store(AbstractBinaryHandlerReflective.java:497)
    at one.microstream.persistence.binary.internal.AbstractBinaryHandlerReflective.store(AbstractBinaryHandlerReflective.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

  • I have found a solution to this problem without the need to change the Java Object graph structure and have Synthetic Classes/static references.

    1. Implement a CustomBinaryHandler for the Object that has the Synthetic Classes/static reference
    2. Override the store method
    3. Override the create method
    4. Override the initializeState method

    Store

    If the reference is to a Synthetic Classes/static references create a new instance of the Object and set the reference to a 'marker'. In my case to a null. Do not update the current object passed into the store method, ensure create a clone and modify the applicable reference. Then call super.store()

    create

    Create an empty instance of the Object

    initializeState

    1. Retrieve the values for the Object
    2. If the value in question has the 'marker' then set it to the Synthetic Classes/static reference
    3. Create a clone object and populate with the values
    4. XReflect.copyFields from the clone to the real instance
    public class ExampleTypeHandler extends CustomBinaryHandler<Example> {
    
        private static Class<Example> handledType() {
            return Example.class; // to get ".class" to work
        }
        
        //the fields to be persisted
        BinaryField<Example> accompanying = Field(Object.class, Example::getAccompanying);
        BinaryField<Example> resulting = Field(Object.class, Example::getResulting);
        
        public ExampleTypeHandler()
        {
            super(handledType());
        }
        
        @Override
        public void store(Binary data, Example dtl, long objectId, PersistenceStoreHandler<Binary> handler) {
            if (dtl.getAccompanying() == MetaDataAccompanying.DUMMY) {
                dtl = Example.of(dtl.getResulting(), null);
            }
            super.store(data, dtl, objectId, handler);
        }
        
        @Override
        public Example create(final Binary data, final PersistenceLoadHandler handler) {
            return Example.of(null, null);
        }
    
        @Override
        public void initializeState(final Binary data, final Example instance, final PersistenceLoadHandler handler) {
            //get the referenced Objects
            Object accompanying = this.accompanying.readReference(data, handler);
            String r = (String)this.resulting.readReference(data, handler);
                
            if (accompanying == null) {
                accompanying = MetaDataAccompanying.DUMMY;
            }
    
            MetaDataAccompanying a = (MetaDataAccompanying) accompanying;
            Example dtl = Example.of(r, a);
            
            XReflect.copyFields(dtl, instance);
        }       
        
    }