Web3j 继承StaticStruct的类所有属性必须为Public,属性的顺序和数量必须和solidity 里面的struct 属性相同,否则属性少了或者多了的时候会出现错位
Web3j 继承StaticStruct的类所有属性不能为private,因为web3j 是通过长度去截取返回值解析成对应的属性进行赋值的。要获取一个list对象时,web3j是按一个类的所有public属性个数去截取总长度的,再进行解析赋值到没一个属性里
StaticStruct类
- import lombok.Data;
- import org.web3j.abi.datatypes.Address;
- import org.web3j.abi.datatypes.StaticStruct;
- import org.web3j.abi.datatypes.Type;
- import org.web3j.abi.datatypes.generated.Uint256;
-
- @Data
- public class ChildStaticStruct extends StaticStruct {
-
- public Uint256 attr1;
- public Uint256 attr2;
- public Address attr3;
-
- public ChildStaticStruct(Uint256 attr1, Uint256 attr2, Address attr3) {
- super(new Type[]{attr1,attr2,attr3});
- }
- }
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.web3j.abi.FunctionEncoder;
- import org.web3j.abi.FunctionReturnDecoder;
- import org.web3j.abi.TypeReference;
- import org.web3j.abi.datatypes.Address;
- import org.web3j.abi.datatypes.DynamicArray;
- import org.web3j.abi.datatypes.Function;
- import org.web3j.abi.datatypes.Type;
- import org.web3j.protocol.Web3j;
- import org.web3j.protocol.core.DefaultBlockParameterName;
- import org.web3j.protocol.core.methods.request.Transaction;
- import org.web3j.protocol.core.methods.response.EthCall;
-
- import java.io.IOException;
- import java.util.Arrays;
- import java.util.List;
-
- public class TestContract {
- private static final Logger logger = LoggerFactory.getLogger(TestContract.class);
- private String address;
- private Web3j web3j;
- public TestContract(String address, Web3j web3j) {
- this.address = address;
- this.web3j = web3j;
- }
-
- public List<ChildStaticStruct> getStaticStructList(String address) throws IOException {
- List<Type> inputParameters = Arrays.asList( new Address(address));
- List<TypeReference<?>> outputParameters = Arrays.asList(new TypeReference
>(){}); - Function function = new Function("getStaticStructList",inputParameters,outputParameters);
- Transaction transaction = Transaction.createEthCallTransaction(null,address, FunctionEncoder.encode(function));
- EthCall response = web3j.ethCall(transaction, DefaultBlockParameterName.LATEST).send();
- List<Type> output = FunctionReturnDecoder.decode(response.getValue(),function.getOutputParameters());
- List<ChildStaticStruct> results = (List<ChildStaticStruct>)output.get(0).getValue();
- return results;
- }
- }
web3j的TypeDecoder 里的decodeArrayElements 验证了是否为StructType子类,
在currOffset += getSingleElementLength(input, currOffset, cls) * 64)判断了截取的长度
- if (StructType.class.isAssignableFrom(cls)) {
- elements = new ArrayList(length);
- currOffset = 0;
-
- for(currOffset = offset; currOffset < length; currOffset += getSingleElementLength(input, currOffset, cls) * 64) {
- if (DynamicStruct.class.isAssignableFrom(cls)) {
- value = decodeDynamicStruct(input, offset + DefaultFunctionReturnDecoder.getDataOffset(input, currOffset, typeReference), TypeReference.create(cls));
- } else {
- value = decodeStaticStruct(input, currOffset, TypeReference.create(cls));
- }
-
- elements.add(value);
- ++currOffset;
- }
-
- String typeName = Utils.getSimpleTypeName(cls);
- return (Type)consumer.apply(elements, typeName);
- }
getSingleElementLength 验证了截取长度是根据public属性数量去截取Utils.staticStructNestedPublicFieldsFlatList(type).size(),pirvate计算长度
- static <T extends Type> int getSingleElementLength(String input, int offset, Class<T> type) {
- if (input.length() == offset) {
- return 0;
- } else if (!DynamicBytes.class.isAssignableFrom(type) && !Utf8String.class.isAssignableFrom(type)) {
- return StaticStruct.class.isAssignableFrom(type) ? Utils.staticStructNestedPublicFieldsFlatList(type).size() : 1;
- } else {
- return decodeUintAsInt(input, offset) / 32 + 2;
- }
- }
staticStructNestedPublicFieldsFlatList方面里面通过Modifier.isPublic(field.getModifiers())过滤了public
- public static List
staticStructNestedPublicFieldsFlatList(Class classType) { - return (List)staticStructsNestedFieldsFlatList(classType).stream().filter((field) -> {
- return Modifier.isPublic(field.getModifiers());
- }).collect(Collectors.toList());
- }
Modifier 里面比较了Public
- public static boolean isPublic(int mod) {
- return (mod & PUBLIC) != 0;
- }