org.fisco.bcos.sdk.v3.codec.Utils Maven / Gradle / Ivy
package org.fisco.bcos.sdk.v3.codec;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.fisco.bcos.sdk.v3.codec.abi.TypeMappingException;
import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicArray;
import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicBytes;
import org.fisco.bcos.sdk.v3.codec.datatypes.DynamicStruct;
import org.fisco.bcos.sdk.v3.codec.datatypes.Fixed;
import org.fisco.bcos.sdk.v3.codec.datatypes.Int;
import org.fisco.bcos.sdk.v3.codec.datatypes.StaticArray;
import org.fisco.bcos.sdk.v3.codec.datatypes.StaticStruct;
import org.fisco.bcos.sdk.v3.codec.datatypes.StructType;
import org.fisco.bcos.sdk.v3.codec.datatypes.Type;
import org.fisco.bcos.sdk.v3.codec.datatypes.TypeReference;
import org.fisco.bcos.sdk.v3.codec.datatypes.Ufixed;
import org.fisco.bcos.sdk.v3.codec.datatypes.Uint;
import org.fisco.bcos.sdk.v3.codec.datatypes.Utf8String;
/** Utility functions. */
public class Utils {
private Utils() {}
public static String getMethodSign(TypeReference typeReference) {
return getMethodSign(typeReference.getType());
}
public static String getTypeName(TypeReference typeReference) {
return getTypeName(typeReference.getType());
}
public static String getMethodSign(java.lang.reflect.Type type) {
try {
Class> cls = Utils.getClassType(type);
if (type instanceof ParameterizedType) { // array
return getParameterizedMethodName(type);
} else { // simple type
return getSimpleMethodSign(cls);
}
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
public static String getTypeName(java.lang.reflect.Type type) {
try {
Class> cls = Utils.getClassType(type);
if (type instanceof ParameterizedType) { // array
return getParameterizedTypeName(type);
} else { // simple type
return getSimpleTypeName(cls);
}
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
private static String getParameterizedMethodName(
java.lang.reflect.Type type) {
try {
Class> cls = Utils.getClassType(type);
if (DynamicArray.class.isAssignableFrom(cls)) {
return getMethodSign(((ParameterizedType) type).getActualTypeArguments()[0]) + "[]";
} else if (StaticArray.class.isAssignableFrom(cls)) {
int length =
Integer.parseInt(
cls.getSimpleName()
.substring(StaticArray.class.getSimpleName().length()));
return getMethodSign(((ParameterizedType) type).getActualTypeArguments()[0])
+ "["
+ length
+ "]";
} else {
throw new UnsupportedOperationException("Invalid type provided " + cls.getName());
}
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
private static String getParameterizedTypeName(
java.lang.reflect.Type type) {
try {
Class> cls = Utils.getClassType(type);
if (DynamicArray.class.isAssignableFrom(cls)) {
return getTypeName(((ParameterizedType) type).getActualTypeArguments()[0]) + "[]";
} else if (StaticArray.class.isAssignableFrom(cls)) {
int length =
Integer.parseInt(
cls.getSimpleName()
.substring(StaticArray.class.getSimpleName().length()));
return getTypeName(((ParameterizedType) type).getActualTypeArguments()[0])
+ "["
+ length
+ "]";
} else {
throw new UnsupportedOperationException("Invalid type provided " + cls.getName());
}
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Invalid class reference provided", e);
}
}
public static String getSimpleMethodSign(Class> type) {
String simpleName = type.getSimpleName().toLowerCase();
if (type.equals(Uint.class)
|| type.equals(Int.class)
|| type.equals(Ufixed.class)
|| type.equals(Fixed.class)) {
return simpleName + "256";
} else if (type.equals(Utf8String.class)) {
return "string";
} else if (type.equals(DynamicBytes.class)) {
return "bytes";
} else if (StructType.class.isAssignableFrom(type)) {
Constructor> constructor =
Arrays.stream(type.getDeclaredConstructors())
.filter(
declaredConstructor ->
Arrays.stream(declaredConstructor.getParameterTypes())
.allMatch(Type.class::isAssignableFrom)
&& declaredConstructor.getParameterTypes()
.length
> 0)
.findAny()
.orElseThrow(
() ->
new RuntimeException(
"TypeReferenced struct must contain a constructor with types that extend Type"));
int length = constructor.getParameterCount();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
for (int i = 0; i < length; i++) {
TypeReference typeReferenceElement =
TypeReference.create(constructor.getGenericParameterTypes()[i]);
stringBuilder.append(getTypeName(typeReferenceElement));
stringBuilder.append(',');
}
stringBuilder.delete(stringBuilder.length() - 1, stringBuilder.length());
stringBuilder.append(')');
return stringBuilder.toString();
} else {
return simpleName;
}
}
public static String getSimpleTypeName(Class> type) {
String simpleName = type.getSimpleName().toLowerCase();
if (type.equals(Uint.class)
|| type.equals(Int.class)
|| type.equals(Ufixed.class)
|| type.equals(Fixed.class)) {
return simpleName + "256";
} else if (type.equals(Utf8String.class)) {
return "string";
} else if (type.equals(DynamicBytes.class)) {
return "bytes";
} else if (StructType.class.isAssignableFrom(type)) {
return type.getName();
} else {
return simpleName;
}
}
@SuppressWarnings("rawtypes")
public static boolean dynamicType(java.lang.reflect.Type type)
throws ClassNotFoundException {
Class cls = Utils.getClassType(type);
// dynamic type
if (Utf8String.class.isAssignableFrom(cls)
|| DynamicBytes.class.isAssignableFrom(cls)
|| DynamicArray.class.isAssignableFrom(cls)) {
return true;
}
// not static type
if (!StaticArray.class.isAssignableFrom(cls)) {
return false;
}
// unpack static array for checking if dynamic type
java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments();
return dynamicType(types[0]);
}
public static int getLength(List parameters) {
int count = 0;
for (final Type type : parameters) {
if (type instanceof StaticArray
&& StaticStruct.class.isAssignableFrom(
((StaticArray) type).getComponentType())) {
count +=
staticStructNestedPublicFieldsFlatList(
((StaticArray) type).getComponentType())
.size()
* ((StaticArray) type).getValue().size();
} else if (type instanceof StaticArray
&& DynamicStruct.class.isAssignableFrom(
((StaticArray) type).getComponentType())) {
count++;
} else if (type instanceof StaticArray) {
count += ((StaticArray) type).getValue().size();
} else {
count++;
}
}
return count;
}
public static List staticStructNestedPublicFieldsFlatList(Class classType) {
return staticStructsNestedFieldsFlatList(classType).stream()
.filter(field -> Modifier.isPublic(field.getModifiers()))
.collect(Collectors.toList());
}
public static List staticStructsNestedFieldsFlatList(Class classType) {
List canonicalFields =
Arrays.stream(classType.getDeclaredFields())
.filter(field -> !StaticStruct.class.isAssignableFrom(field.getType()))
.collect(Collectors.toList());
List nestedFields =
Arrays.stream(classType.getDeclaredFields())
.filter(field -> StaticStruct.class.isAssignableFrom(field.getType()))
.map(
field ->
staticStructsNestedFieldsFlatList(
(Class) field.getType()))
.flatMap(Collection::stream)
.collect(Collectors.toList());
return Stream.concat(canonicalFields.stream(), nestedFields.stream())
.collect(Collectors.toList());
}
public static int getOffset(java.lang.reflect.Type type)
throws ClassNotFoundException {
if (Utils.dynamicType(type)) {
return 1;
}
Class cls = Utils.getClassType(type);
if (StaticArray.class.isAssignableFrom(cls)) {
int length =
Integer.parseInt(
cls.getSimpleName()
.substring(StaticArray.class.getSimpleName().length()));
java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments();
return getOffset(types[0]) * length;
} else {
return 1;
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
public static Class getClassType(java.lang.reflect.Type type)
throws ClassNotFoundException {
if (type instanceof ParameterizedType) {
return (Class) ((ParameterizedType) type).getRawType();
} else {
return (Class) Class.forName(type.getTypeName());
}
}
@SuppressWarnings("unchecked")
public static Class getParameterizedTypeFromArray(
TypeReference typeReference) throws ClassNotFoundException {
java.lang.reflect.Type type = typeReference.getType();
java.lang.reflect.Type[] types = ((ParameterizedType) type).getActualTypeArguments();
return Utils.getClassType(types[0]);
}
@SuppressWarnings("unchecked")
public static List> convert(List> input) {
List> result = new ArrayList<>(input.size());
result.addAll(
input.stream()
.map(typeReference -> (TypeReference) typeReference)
.collect(Collectors.toList()));
return result;
}
public static , E extends Type> List typeMap(
List> input, Class outerDestType, Class innerType) {
List result = new ArrayList<>();
try {
Constructor constructor = outerDestType.getDeclaredConstructor(List.class);
for (List ts : input) {
E e = constructor.newInstance(typeMap(ts, innerType));
result.add(e);
}
} catch (NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException e) {
throw new TypeMappingException(e);
}
return result;
}
public static > List typeMap(List input, Class destType)
throws TypeMappingException {
List result = new ArrayList(input.size());
if (!input.isEmpty()) {
try {
Constructor constructor;
if (input.get(0) instanceof List) {
constructor = destType.getDeclaredConstructor(List.class);
} else {
constructor = destType.getDeclaredConstructor(input.get(0).getClass());
}
for (T value : input) {
result.add(constructor.newInstance(value));
}
} catch (NoSuchMethodException
| IllegalAccessException
| InvocationTargetException
| InstantiationException e) {
throw new TypeMappingException(e);
}
}
return result;
}
@SuppressWarnings("rawtypes")
public static List typeMapWithoutGenericType(List input, Class destType)
throws TypeMappingException {
List result = new ArrayList(input.size());
if (!input.isEmpty()) {
try {
Constructor constructor = destType.getDeclaredConstructor(input.get(0).getClass());
for (Object value : input) {
result.add(constructor.newInstance(value));
}
} catch (NoSuchMethodException
| IllegalAccessException
| InvocationTargetException
| InstantiationException e) {
throw new TypeMappingException(e);
}
}
return result;
}
}