All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.klaytn.caver.abi.Utils Maven / Gradle / Ivy

There is a newer version: 1.12.2-android
Show newest version
/*
 * Modifications copyright 2021 The caver-java Authors
 * Copyright 2019 Web3 Labs Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * This file is derived from web3j/abi/src/main/java/org/web3j/abi/Utils.java (2021/04/05).
 * Modified and improved for the caver-java development.
 */

package com.klaytn.caver.abi;

import com.klaytn.caver.abi.datatypes.*;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
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;

/** Utility functions. */
public class Utils {
    private Utils() {}

    static  String getTypeName(TypeReference typeReference) {
        try {
            java.lang.reflect.Type reflectedType = typeReference.getType();

            Class type;
            if (reflectedType instanceof ParameterizedType) {
                type = (Class) ((ParameterizedType) reflectedType).getRawType();
                return getParameterizedTypeName(typeReference, type);
            } else {
                type = Class.forName(reflectedType.getTypeName());
                return getSimpleTypeName(type);
            }
        } catch (ClassNotFoundException e) {
            throw new UnsupportedOperationException("Invalid class reference provided", e);
        }
    }

    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;
        }
    }

    static  String getParameterizedTypeName(
            TypeReference typeReference, Class type) {

        try {
            if (type.equals(DynamicArray.class)) {
                Class parameterizedType = getParameterizedTypeFromArray(typeReference);
                String parameterizedTypeName = getSimpleTypeName(parameterizedType);
                return parameterizedTypeName + "[]";
            } else if (type.equals(StaticArray.class)) {
                Class parameterizedType = getParameterizedTypeFromArray(typeReference);
                String parameterizedTypeName = getSimpleTypeName(parameterizedType);
                return parameterizedTypeName
                        + "["
                        + ((TypeReference.StaticArrayTypeReference) typeReference).getSize()
                        + "]";
            } else {
                throw new UnsupportedOperationException("Invalid type provided " + type.getName());
            }
        } catch (ClassNotFoundException e) {
            throw new UnsupportedOperationException("Invalid class reference provided", e);
        }
    }

    @SuppressWarnings("unchecked")
    static  Class getParameterizedTypeFromArray(TypeReference typeReference)
            throws ClassNotFoundException {

        java.lang.reflect.Type type = typeReference.getType();
        java.lang.reflect.Type[] typeArguments =
                ((ParameterizedType) type).getActualTypeArguments();

        String parameterizedTypeName = typeArguments[0].getTypeName();
        return (Class) Class.forName(parameterizedTypeName);
    }

    @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(Class.class, List.class);
            for (List ts : input) {
                E e = constructor.newInstance(innerType, 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 com.klaytn.caver.abi.TypeMappingException {

        List result = new ArrayList<>(input.size());

        if (!input.isEmpty()) {
            try {
                Constructor 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;
    }


    static int getStaticArrayElementSize(StaticArray staticArray) {
        int count = 0;

        if(StaticStruct.class.isAssignableFrom(staticArray.getComponentType())) {
            count += staticArray.getValue().size() * getStaticStructComponentSize((StaticStruct)staticArray.getValue().get(0));
        } else if(StaticArray.class.isAssignableFrom(staticArray.getComponentType())) {
            count += staticArray.getValue().size() * getStaticArrayElementSize((StaticArray)staticArray.getValue().get(0));
        } else {
            count += staticArray.getValue().size();
        }

        return count;
    }

    static int getStaticArrayElementSize(TypeReference.StaticArrayTypeReference arrayTypeRef) throws ClassNotFoundException {
        int count = 0;
        TypeReference baseTypeRef = arrayTypeRef.getSubTypeReference();

        if(StaticStruct.class.isAssignableFrom(baseTypeRef.getClassType())) {
            count += arrayTypeRef.getSize() * getStaticStructComponentSize((TypeReference.StructTypeReference) baseTypeRef);
        } else if(StaticArray.class.isAssignableFrom(baseTypeRef.getClassType())) {
            count += arrayTypeRef.getSize() * getStaticArrayElementSize((TypeReference.StaticArrayTypeReference)baseTypeRef);
        } else {
            count += arrayTypeRef.getSize();
        }

        return count;
    }

    public static int getStaticStructComponentSize(StaticStruct staticStruct) {
        int count = 0;
        for(int i=0; i< staticStruct.getValue().size(); i++) {
            Type type = staticStruct.getValue().get(i);

            if(StaticStruct.class.isAssignableFrom(type.getClass())) {
                count += getStaticStructComponentSize((StaticStruct)type);
            } else if(StaticArray.class.isAssignableFrom(type.getClass())) {
                count += getStaticArrayElementSize((StaticArray)type);
            } else {
                count ++;
            }
        }
        return count;
    }

    static int getStaticStructComponentSize(TypeReference.StructTypeReference typeReference) throws ClassNotFoundException {
        int count = 0;
        for(int i=0; i< typeReference.getTypeList().size(); i++) {
            TypeReference componentTypeRef = (TypeReference)typeReference.getTypeList().get(i);

            if(StaticStruct.class.isAssignableFrom(componentTypeRef.getClassType())) {
                count += getStaticStructComponentSize((TypeReference.StructTypeReference)componentTypeRef);
            } else if(StaticArray.class.isAssignableFrom(componentTypeRef.getClassType())) {
                TypeReference.StaticArrayTypeReference arrayTypeReference = (TypeReference.StaticArrayTypeReference) componentTypeRef;
                count += getStaticArrayElementSize(arrayTypeReference);
            } else {
                count ++;
            }
        }
        return count;
    }

}