Java microstream列表对象未正确存储。

huangapple go评论75阅读模式
英文:

Java microstream List Object not stored correctly

问题

我有以下的对象结构,它扩展了ArrayList。当检索它时,List为null,因此没有将任何值存储在microstream对象图中。不确定这是否是:

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

创建FooTable对象的代码以及toString的结果如下:

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

将FooTable存储在MicroStream中。停止/启动应用程序/数据库并检索FooTable,List为null。有趣的是,在检查对象变量时,'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 {

    int getTableNo();
    int getDatatableNo();
}
英文:

I have the below object structure which extends ArrayList. When it is retrieved the List is null and so none of the values are stored within the microstream object graph. Not sure if this is either

  1. a bug
  2. unsupported feature
  3. A CustomHandler must be implemented

The code for creating the FooTable Object and toString results in

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

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

Store FooTable in MicroStream. Stop/Start the app/DB and retrieve FooTable and the List is null. Interestingly when inspection the object variable 'size=3'.
It appears microstream cannot see the fact this object extends List and only persists the other values ignoring the List.

Any advise on how to resolve this without changing the object structure.

Note: Lombok is being used here for brevity.

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

@Getter
@Setter
@ToString(callSuper = true)
public class FooTable extends TableListImpl&lt;String&gt; {

	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&lt;E&gt; extends ArrayList&lt;E&gt; implements TableList&lt;E&gt; {

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

public interface TableList&lt;E&gt; extends List&lt;E&gt;, Table {

}
public interface Table {

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

答案1

得分: 3

以下是要翻译的内容:

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

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&lt;FooTable&gt;
{
	//要存储的字段包括:
	//来自TableListImpl的private final int tableNo
	//来自TableListImpl的private final int datatableNo
	//来自FooTable的private String baz
	//来自ArrayList的transient Object[] elementData
	
	//定义用于存储类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, &quot;tableNo&quot;),
				CustomField(int.class, &quot;datatableNo&quot;),
				CustomField(String.class, &quot;baz&quot;)
				)
			);
	}
		
	@Override
	public void iterateLoadableReferences(final Binary data, final PersistenceReferenceLoader iterator)
	{
		//注册所有需要恢复的引用项
		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&lt;Binary&gt; handler)
	{
		//将列表中的项目存储起来
		data.storeIterableAsList(
			this.typeId()         ,
			objectId              ,
			BINARY_OFFSET_ELEMENTS,
			instance              ,
			instance.size()       ,
			handler
		);
		
		//直接存储int值
		data.store_int(BINARY_OFFSET_TABLE_NO     , instance.getTableNo());
		data.store_int(BINARY_OFFSET_DATA_TABLE_NO, instance.getDatatableNo());
		
		//存储对String字段&quot;baz&quot;的引用,并在需要时处理String本身
		data.store_long(BINARY_OFFSET_BAZ         , handler.apply(instance.getBaz()));
	}

	@Override
	public FooTable create(final Binary data, final PersistenceLoadHandler handler)
	{
		//读取int值
		//创建一个空实例
		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.clear();
				
		//获取所有列表元素
		data.collectObjectReferences(
			BINARY_OFFSET_ELEMENTS,
			X.checkArrayRange(this.getElementCount(data)),
			handler,
			e -&gt;
				instance.add((String) e)
		);
		
		//获取&quot;baz&quot;
		instance.setBaz((String) handler.lookupObject(data.read_long(BINARY_OFFSET_BAZ)));
	}

}

希望这对你有所帮助。

英文:

The issue is not really a bug. The fact that no list elements are stored is caused by the java.util.ArrayList<E> implementation that marks the underlaying object array as transient. Therefore, Microstream does not persist it by default.
But a custom type handler can solve that.
Here is an example how such a type-handler for the class FooTable may look like:

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&lt;FooTable&gt;
{
//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, &quot;tableNo&quot;),
CustomField(int.class, &quot;datatableNo&quot;),
CustomField(String.class, &quot;baz&quot;)
)
);
}
@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&lt;Binary&gt; 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 &quot;baz&quot; 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 -&gt;
instance.add((String) e)
);
//get &quot;baz&quot;
instance.setBaz((String) handler.lookupObject(data.read_long(BINARY_OFFSET_BAZ)));
}
}

huangapple
  • 本文由 发表于 2020年8月8日 05:29:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/63309366.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定