Java 微流列表对象存储不正确
Java microstream List Object not stored correctly
我有以下扩展 ArrayList 的对象结构。当它被检索时,列表为空,因此 none 的值存储在微流对象图中。不确定这是不是
- 一个错误
- 不支持的功能
- 必须实现 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)));
}
}
我有以下扩展 ArrayList 的对象结构。当它被检索时,列表为空,因此 none 的值存储在微流对象图中。不确定这是不是
- 一个错误
- 不支持的功能
- 必须实现 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)));
}
}