package org.web3j.codegen; import java.io.IOException; import javax.lang.model.element.Modifier; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.MethodSpec; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.WildcardTypeName; import org.web3j.abi.datatypes.Address; import org.web3j.abi.datatypes.Bool; import org.web3j.abi.datatypes.Bytes; import org.web3j.abi.datatypes.DynamicBytes; import org.web3j.abi.datatypes.Fixed; import org.web3j.abi.datatypes.Int; import org.web3j.abi.datatypes.Type; import org.web3j.abi.datatypes.Ufixed; import org.web3j.abi.datatypes.Uint; import org.web3j.abi.datatypes.Utf8String; /** * Generator class for creating all the different numeric type variants. */ public class AbiTypesMapperGenerator extends Generator { private static final String TYPE = "type"; public static void main(String[] args) throws Exception { AbiTypesMapperGenerator abiTypesMapperGenerator = new AbiTypesMapperGenerator(); if (args.length == 1) { abiTypesMapperGenerator.generate(args[0]); } else { abiTypesMapperGenerator.generate( System.getProperty("user.dir") + "/core/src/main/java/"); } } private void generate(String destinationDir) throws IOException { String typesPackageName = "org.web3j.abi.datatypes"; String autoGeneratedTypesPackageName = typesPackageName + ".generated"; MethodSpec.Builder builder = MethodSpec.methodBuilder("getType") .addModifiers(Modifier.PUBLIC, Modifier.STATIC) .addParameter(String.class, TYPE) .returns( ParameterizedTypeName.get(ClassName.get(Class.class), WildcardTypeName.subtypeOf(Object.class)) ) .beginControlFlow("switch (type)"); builder = addTypes(builder, typesPackageName); builder = addGeneratedTypes(builder, autoGeneratedTypesPackageName); builder = builder.addStatement("default:\nthrow new $T($S\n+ $N)", UnsupportedOperationException.class, "Unsupported type encountered: ", TYPE); builder.endControlFlow(); MethodSpec methodSpec = builder.build(); MethodSpec constructorSpec = MethodSpec.constructorBuilder() .addModifiers(Modifier.PRIVATE) .build(); TypeSpec typeSpec = TypeSpec .classBuilder("AbiTypes") .addJavadoc(buildWarning(AbiTypesMapperGenerator.class)) .addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addMethod(constructorSpec) .addMethod(methodSpec) .build(); write(autoGeneratedTypesPackageName, typeSpec, destinationDir); } private MethodSpec.Builder addTypes(MethodSpec.Builder builder, String packageName) { builder = addStatement(builder, packageName, Address.TYPE_NAME, Address.class.getSimpleName()); builder = addStatement(builder, packageName, Bool.TYPE_NAME, Bool.class.getSimpleName()); builder = addStatement(builder, packageName, Utf8String.TYPE_NAME, Utf8String.class.getSimpleName()); builder = addStatement(builder, packageName, DynamicBytes.TYPE_NAME, DynamicBytes.class.getSimpleName()); // TODO: Fixed array & dynamic array support return builder; } private MethodSpec.Builder addGeneratedTypes(MethodSpec.Builder builder, String packageName) { builder = generateIntTypes(builder, packageName); // TODO: Enable once Solidity supports fixed types - see // https://github.com/ethereum/solidity/issues/409 // builder = generateFixedTypes(builder, packageName); builder = generateFixedBytesTypes(builder, packageName); return builder; } private MethodSpec.Builder generateIntTypes(MethodSpec.Builder builder, String packageName) { for (int bitSize = 8; bitSize <= Type.MAX_BIT_LENGTH; bitSize += 8) { builder = addStatement(builder, packageName, Uint.TYPE_NAME + bitSize, Uint.class.getSimpleName() + bitSize); builder = addStatement(builder, packageName, Int.TYPE_NAME + bitSize, Int.class.getSimpleName() + bitSize); } return builder; } private MethodSpec.Builder generateFixedTypes(MethodSpec.Builder builder, String packageName) { for (int mBitSize = 8, nBitSize = Type.MAX_BIT_LENGTH - 8; mBitSize < Type.MAX_BIT_LENGTH && nBitSize > 0; mBitSize += 8, nBitSize -= 8) { String suffix = mBitSize + "x" + nBitSize; builder = addStatement( builder, packageName, Ufixed.TYPE_NAME + suffix, Ufixed.class.getSimpleName() + suffix); builder = addStatement( builder, packageName, Fixed.TYPE_NAME + suffix, Fixed.class.getSimpleName() + suffix); } return builder; } private MethodSpec.Builder generateFixedBytesTypes(MethodSpec.Builder builder, String packageName) { for (int byteSize = 1; byteSize <= 32; byteSize++) { builder = addStatement(builder, packageName, Bytes.TYPE_NAME + byteSize, Bytes.class.getSimpleName() + byteSize); } return builder; } private MethodSpec.Builder addStatement(MethodSpec.Builder builder, String packageName, String typeName, String className) { return builder.addStatement( "case \"$L\":\nreturn $T.class", typeName, ClassName.get(packageName, className)); } }