Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support codegen directly from Truffle json contract files #228

Merged
merged 19 commits into from
Nov 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Features
- Ethereum wallet support
- Auto-generation of Java smart contract wrappers to create, deploy, transact with and call smart
contracts from native Java code
- from solc output; or
- from Truffle `.json` contract files.
- Reactive-functional API for working with filters
- Support for Parity's
`Personal <https://github.com/paritytech/parity/wiki/JSONRPC-personal-module>`__, and Geth's
Expand Down Expand Up @@ -251,7 +253,24 @@ Now you can create and deploy your smart contract:
GAS_PRICE, GAS_LIMIT,
<param1>, ..., <paramN>).send(); // constructor params

Or use an existing contract:
Alternatively, if you use `Truffle <http://truffleframework.com/>`_, you can make use of its `.json` output files:

.. code-block:: bash

# Inside your Truffle project
$ truffle compile
$ truffle deploy

Then generate the wrapper code using web3j's `Command line tools`_:

.. code-block:: bash

$ cd /path/to/your/web3j/java/project
$ web3j truffle generate /path/to/<truffle-smart-contract-output>.json -o /path/to/src/main/java -p com.your.organisation.name

Whether using `Truffle` or `solc` directly, either way you get a ready-to-use Java wrapper for your contract.

So, to use an existing contract:

.. code-block:: java

Expand Down
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,74 @@ 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