Skip to content

Commit

Permalink
Support for generating Java source from Truffle .json contract files.
Browse files Browse the repository at this point in the history
  • Loading branch information
eepstein committed Nov 9, 2017
1 parent c3b3fd6 commit c503a2b
Show file tree
Hide file tree
Showing 15 changed files with 2,612 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.web3j.codegen;

import java.io.File;

import static org.web3j.codegen.Console.exitError;

/**
* Abstract base class for the concrete function wrapper generators.
*/
abstract class FunctionWrapperGenerator {

static final String JAVA_TYPES_ARG = "--javaTypes";
static final String SOLIDITY_TYPES_ARG = "--solidityTypes";

final File destinationDirLocation;
final String basePackageName;
final boolean useJavaNativeTypes;

FunctionWrapperGenerator(
String destinationDirLocation,
String basePackageName,
boolean useJavaNativeTypes) {

this.destinationDirLocation = new File(destinationDirLocation);
this.basePackageName = basePackageName;
this.useJavaNativeTypes = useJavaNativeTypes;
}

static boolean useJavaNativeTypes(String argVal, String usageString) {
boolean useJavaNativeTypes = true;
if (SOLIDITY_TYPES_ARG.equals(argVal)) {
useJavaNativeTypes = false;
} else if (JAVA_TYPES_ARG.equals(argVal)) {
useJavaNativeTypes = true;
} else {
exitError(usageString);
}
return useJavaNativeTypes;
}

static String parsePositionalArg(String[] args, int idx) {
if (args != null && args.length > idx) {
return args[idx];
} else {
return "";
}
}

static String parseParameterArgument(String[] args, String... parameters) {
for (String parameter : parameters) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals(parameter)
&& i + 1 < args.length) {
String parameterValue = args[i + 1];
if (!parameterValue.startsWith("-")) {
return parameterValue;
}
}
}
}
return "";
}

static String getFileNameNoExtension(String fileName) {
String[] splitName = fileName.split("\\.(?=[^.]*$)");
return splitName[0];
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.lang.model.element.Modifier;

Expand Down Expand Up @@ -81,24 +83,73 @@ public SolidityFunctionWrapper(boolean useNativeJavaTypes) {
this.useNativeJavaTypes = useNativeJavaTypes;
}

@SuppressWarnings("unchecked")
public void generateJavaFiles(
String contractName, String bin, String abi, String destinationDir,
String basePackageName)
throws IOException, ClassNotFoundException {
generateJavaFiles(contractName, bin,
loadContractDefinition(abi),
destinationDir, basePackageName,
null);
}

void generateJavaFiles(
String contractName, String bin, List<AbiDefinition> abi, String destinationDir,
String basePackageName, Map<String, String> addresses)
throws IOException, ClassNotFoundException {
String className = Strings.capitaliseFirstLetter(contractName);

TypeSpec.Builder classBuilder = createClassBuilder(className, bin);

classBuilder.addMethod(buildConstructor(Credentials.class, CREDENTIALS));
classBuilder.addMethod(buildConstructor(TransactionManager.class, TRANSACTION_MANAGER));
classBuilder.addMethods(
buildFunctionDefinitions(className, classBuilder, loadContractDefinition(abi)));
buildFunctionDefinitions(className, classBuilder, abi));
classBuilder.addMethod(buildLoad(className, Credentials.class, CREDENTIALS));
classBuilder.addMethod(buildLoad(className, TransactionManager.class, TRANSACTION_MANAGER));

addAddressesSupport(classBuilder, addresses);

write(basePackageName, classBuilder.build(), destinationDir);
}

private void addAddressesSupport(TypeSpec.Builder classBuilder, Map<String, String> addresses) {
if (addresses != null) {

ClassName stringType = ClassName.get(String.class);
ClassName mapType = ClassName.get(HashMap.class);
TypeName mapStringString = ParameterizedTypeName.get(mapType, stringType, stringType);
FieldSpec addressesStaticField = FieldSpec
.builder(mapStringString, "_addresses",
Modifier.PROTECTED, Modifier.STATIC, Modifier.FINAL)
.build();
classBuilder.addField(addressesStaticField);

final CodeBlock.Builder staticInit = CodeBlock.builder();
staticInit.addStatement("_addresses = new HashMap<>()");
addresses.forEach((k, v) ->
staticInit.addStatement(String.format("_addresses.put(\"%1s\", \"%2s\")", k, v))
);
classBuilder.addStaticBlock(staticInit.build());

// See org.web3j.tx.Contract#getStaticDeployedAddress(String)
MethodSpec getAddress = MethodSpec
.methodBuilder("getStaticDeployedAddress")
.addModifiers(Modifier.PROTECTED)
.returns(stringType)
.addParameter(stringType, "networkId")
.addCode(CodeBlock
.builder()
.addStatement("return _addresses.get(networkId)")
.build())
.build();
classBuilder.addMethod(getAddress);

}
}


private TypeSpec.Builder createClassBuilder(String className, String binary) {

String javadoc = CODEGEN_WARNING + getWeb3jVersion();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,16 @@
/**
* Java wrapper source code generator for Solidity ABI format.
*/
public class SolidityFunctionWrapperGenerator {
public class SolidityFunctionWrapperGenerator extends FunctionWrapperGenerator {

private static final String USAGE = "solidity generate "
+ "[--javaTypes|--solidityTypes] "
+ "<input binary file>.bin <input abi file>.abi "
+ "-p|--package <base package name> "
+ "-o|--output <destination base directory>";

static final String JAVA_TYPES_ARG = "--javaTypes";
static final String SOLIDITY_TYPES_ARG = "--solidityTypes";

private String binaryFileLocation;
private String absFileLocation;
private File destinationDirLocation;
private String basePackageName;
private boolean useJavaNativeTypes;
private final String binaryFileLocation;
private final String absFileLocation;

private SolidityFunctionWrapperGenerator(
String binaryFileLocation,
Expand All @@ -42,11 +36,9 @@ private SolidityFunctionWrapperGenerator(
String basePackageName,
boolean useJavaNativeTypes) {

super(destinationDirLocation, basePackageName, useJavaNativeTypes);
this.binaryFileLocation = binaryFileLocation;
this.absFileLocation = absFileLocation;
this.destinationDirLocation = new File(destinationDirLocation);
this.basePackageName = basePackageName;
this.useJavaNativeTypes = useJavaNativeTypes;
}

public static void run(String[] args) throws Exception {
Expand All @@ -72,14 +64,7 @@ public static void main(String[] args) throws Exception {
exitError(USAGE);
}

boolean useJavaNativeTypes = true;
if (fullArgs[0].equals(SOLIDITY_TYPES_ARG)) {
useJavaNativeTypes = false;
} else if (fullArgs[0].equals(JAVA_TYPES_ARG)) {
useJavaNativeTypes = true;
} else {
exitError(USAGE);
}
boolean useJavaNativeTypes = useJavaNativeTypes(fullArgs[0], USAGE);

String binaryFileLocation = parsePositionalArg(fullArgs, 1);
String absFileLocation = parsePositionalArg(fullArgs, 2);
Expand All @@ -102,27 +87,11 @@ public static void main(String[] args) throws Exception {
.generate();
}

private static String parsePositionalArg(String[] args, int idx) {
if (args != null && args.length > idx) {
return args[idx];
} else {
return "";
}
}

private static String parseParameterArgument(String[] args, String... parameters) {
for (String parameter : parameters) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals(parameter)
&& i + 1 < args.length) {
String parameterValue = args[i + 1];
if (!parameterValue.startsWith("-")) {
return parameterValue;
}
}
}
}
return "";
static List<AbiDefinition> loadContractDefinition(File absFile)
throws IOException {
ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class);
return Arrays.asList(abiDefinition);
}

private void generate() throws IOException, ClassNotFoundException {
Expand Down Expand Up @@ -157,15 +126,5 @@ private void generate() throws IOException, ClassNotFoundException {
}
}

private static List<AbiDefinition> loadContractDefinition(File absFile)
throws IOException {
ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper();
AbiDefinition[] abiDefinition = objectMapper.readValue(absFile, AbiDefinition[].class);
return Arrays.asList(abiDefinition);
}

static String getFileNameNoExtension(String fileName) {
String[] splitName = fileName.split("\\.(?=[^.]*$)");
return splitName[0];
}
}
Loading

0 comments on commit c503a2b

Please sign in to comment.