Java 微流列表对象存储不正确

Java microstream List Object not stored correctly

我有以下扩展 ArrayList 的对象结构。当它被检索时,列表为空,因此 none 的值存储在微流对象图中。不确定这是不是

  1. 一个错误
  2. 不支持的功能
  3. 必须实现 CustomHandler

创建 FooTable 对象和 toString 的代码生成

FooTable(super=TableListImpl(super=[a, b, c], tableNo=1, datatableNo=2), baz=baz)

        FooTable foo = new FooTable(1,2);
        foo.setBaz("baz");
        foo.add("a");
        foo.add("b");
        foo.add("c");
        System.out.println(foo1.toString());

将 FooTable 存储在 MicroStream 中。 Stop/Start app/DB 并检索 FooTable 并且列表为空。有趣的是,当检查对象变量 'size=3' 时。 microstream 似乎看不到这个对象扩展了 List 并且只保留其他值而忽略了 List 的事实。

关于如何在不更改对象结构的情况下解决此问题的任何建议。

注意:为简洁起见,此处使用 Lombok。

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString(callSuper = true)
public class FooTable extends TableListImpl<String> {

    public FooTable(int tableNo, int datatableNo) {
        super(tableNo, datatableNo);
    }
    
    private static final long serialVersionUID = 1L;
    private String baz;
    
}
import java.util.ArrayList;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.ToString;

@RequiredArgsConstructor
@Getter
@ToString(callSuper = true)
public abstract class TableListImpl<E> extends ArrayList<E> implements TableList<E> {

    private static final long serialVersionUID = 1L;
    private final int tableNo;
    private final int datatableNo;
    
}
import java.util.List;

public interface TableList<E> extends List<E>, Table {

}
public interface Table {

    public int getTableNo();
    public int getDatatableNo();
}

这个问题并不是真正的错误。没有存储列表元素的事实是由 java.util.ArrayList 将底层对象数组标记为瞬态的实现引起的。因此,Microstream 默认不持久化它。 但是自定义类型处理程序可以解决这个问题。 以下是 class FooTable 的 type-handler 的示例:

import one.microstream.X;
import one.microstream.persistence.binary.internal.AbstractBinaryHandlerCustomCollection;
import one.microstream.persistence.binary.types.Binary;
import one.microstream.persistence.types.PersistenceLoadHandler;
import one.microstream.persistence.types.PersistenceReferenceLoader;
import one.microstream.persistence.types.PersistenceStoreHandler;

public class FooTableTypeHandler extends AbstractBinaryHandlerCustomCollection<FooTable>
{
    //the fields to be stored are:
    //private final int tableNo from TableListImpl
    //private final int datatableNo from TableListImpl;
    //private String baz from FooTable
    //transient Object[] elementData from ArrayList
    
    //define the binary layout used for storing the class FooTable
    private static final long BINARY_OFFSET_TABLE_NO      = 0;
    private static final long BINARY_OFFSET_DATA_TABLE_NO = BINARY_OFFSET_TABLE_NO + Integer.BYTES;
    private static final long BINARY_OFFSET_BAZ           = BINARY_OFFSET_DATA_TABLE_NO + Integer.BYTES;
    private static final long BINARY_OFFSET_ELEMENTS      = BINARY_OFFSET_BAZ + Binary.referenceBinaryLength(1);
            
    protected FooTableTypeHandler()
    {
        super (FooTable.class,
            SimpleArrayFields(
                CustomField(int.class, "tableNo"),
                CustomField(int.class, "datatableNo"),
                CustomField(String.class, "baz")
                )
            );
    }
        
    @Override
    public void iterateLoadableReferences(final Binary data, final PersistenceReferenceLoader iterator)
    {
        //register all referenced items that need to be restored too
        data.iterateListElementReferences(BINARY_OFFSET_ELEMENTS, iterator);
        iterator.acceptObjectId(data.read_long(BINARY_OFFSET_BAZ));
    }
    
    @Override
    public void store(final Binary data, final FooTable instance, final long objectId, final PersistenceStoreHandler<Binary> handler)
    {
        //store items in the list
        data.storeIterableAsList(
            this.typeId()         ,
            objectId              ,
            BINARY_OFFSET_ELEMENTS,
            instance              ,
            instance.size()       ,
            handler
        );
        
        //store int values directly
        data.store_int(BINARY_OFFSET_TABLE_NO     , instance.getTableNo());
        data.store_int(BINARY_OFFSET_DATA_TABLE_NO, instance.getDatatableNo());
        
        //store a reference to the String field "baz" and handle the String itself, if needed
        data.store_long(BINARY_OFFSET_BAZ         , handler.apply(instance.getBaz()));
    }

    @Override
    public FooTable create(final Binary data, final PersistenceLoadHandler handler)
    {
        //read the int values
        //create empty instance
        return new FooTable(
            data.read_int(BINARY_OFFSET_TABLE_NO),
            data.read_int(BINARY_OFFSET_DATA_TABLE_NO));
    }
    
    private long getElementCount(final Binary data)
    {
        return data.getListElementCountReferences(BINARY_OFFSET_ELEMENTS);
    }
    
    @Override
    public void updateState(final Binary data, final FooTable instance, final PersistenceLoadHandler handler)
    {
        // instance must be cleared in case an existing one is updated
        instance.clear();
                
        //get all list elements
        data.collectObjectReferences(
            BINARY_OFFSET_ELEMENTS,
            X.checkArrayRange(this.getElementCount(data)),
            handler,
            e ->
                instance.add((String) e)
        );
        
        //get "baz"
        instance.setBaz((String) handler.lookupObject(data.read_long(BINARY_OFFSET_BAZ)));
    }

}