diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java index 674d24ac9..80435c5c4 100644 --- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java +++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java @@ -418,10 +418,22 @@ FieldSpec createBinaryDefinition(String binary) { .build(); } - private FieldSpec createEventDefinition(String name, List parameters) { + private FieldSpec createEventDefinition( + String name, + List parameters, + Map eventsCount, + AbiDefinition event + ) { CodeBlock initializer = buildVariableLengthEventInitializer(name, parameters); + Integer occurrences = eventsCount.get(name); + if (occurrences > 1) { + event.setName(name + (occurrences - 1)); + eventsCount.replace(name, occurrences - 1); + name = event.getName(); + } + return FieldSpec.builder(Event.class, buildEventDefinitionName(name)) .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) .initializer(initializer) @@ -432,13 +444,14 @@ private String buildEventDefinitionName(String eventName) { return eventName.toUpperCase() + "_EVENT"; } - private List buildFunctionDefinitions( + List buildFunctionDefinitions( String className, TypeSpec.Builder classBuilder, List functionDefinitions) throws ClassNotFoundException { Set duplicateFunctionNames = getDuplicateFunctionNames(functionDefinitions); + Map eventsCount = getDuplicatedEventNames(functionDefinitions); List methodSpecs = new ArrayList<>(); for (AbiDefinition functionDefinition : functionDefinitions) { if (functionDefinition.getType().equals(TYPE_FUNCTION)) { @@ -446,12 +459,35 @@ private List buildFunctionDefinitions( boolean useUpperCase = !duplicateFunctionNames.contains(functionName); methodSpecs.addAll(buildFunctions(functionDefinition, useUpperCase)); } else if (functionDefinition.getType().equals(TYPE_EVENT)) { - methodSpecs.addAll(buildEventFunctions(functionDefinition, classBuilder)); + methodSpecs.addAll( + buildEventFunctions(functionDefinition, classBuilder, eventsCount) + ); } } return methodSpecs; } + Map getDuplicatedEventNames(List functionDefinitions) { + Map countMap = new HashMap<>(); + + functionDefinitions.stream() + .filter( + function -> + TYPE_EVENT.equals(function.getType()) && function.getName() != null) + .forEach( + function -> { + String functionName = function.getName(); + if (countMap.containsKey(functionName)) { + int count = countMap.get(functionName); + countMap.put(functionName, count + 1); + } else { + countMap.put(functionName, 1); + } + }); + + return countMap; + } + private List buildStructTypes(final List functionDefinitions) throws ClassNotFoundException { final List orderedKeys = extractStructs(functionDefinitions); @@ -1917,11 +1953,12 @@ private static String getEventFromLogFunctionName(String functionName) { } List buildEventFunctions( - AbiDefinition functionDefinition, TypeSpec.Builder classBuilder) + AbiDefinition functionDefinition, + TypeSpec.Builder classBuilder, + Map eventsCount + ) throws ClassNotFoundException { - String functionName = functionDefinition.getName(); List inputs = functionDefinition.getInputs(); - String responseClassName = Strings.capitaliseFirstLetter(functionName) + "EventResponse"; List parameters = new ArrayList<>(); List indexedParameters = new ArrayList<>(); @@ -1946,7 +1983,15 @@ List buildEventFunctions( parameters.add(parameter); } - classBuilder.addField(createEventDefinition(functionName, parameters)); + String functionName = functionDefinition.getName(); + + classBuilder.addField(createEventDefinition( + functionName, parameters, eventsCount, functionDefinition + )); + + functionName = functionDefinition.getName(); + + String responseClassName = Strings.capitaliseFirstLetter(functionName) + "EventResponse"; classBuilder.addType( buildEventResponseObject( diff --git a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java index 156641638..3624bd5b4 100644 --- a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java +++ b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java @@ -685,7 +685,11 @@ public void testBuildEventConstantMultipleValueReturn() throws Exception { TypeSpec.Builder builder = TypeSpec.classBuilder("testClass"); builder.addMethods( - solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder)); + solidityFunctionWrapper.buildEventFunctions( + functionDefinition, + builder, + solidityFunctionWrapper.getDuplicatedEventNames( + Collections.singletonList(functionDefinition)))); String expected = "class testClass {\n" @@ -773,7 +777,11 @@ public void testBuildEventWithNamedAndNoNamedParameters() throws Exception { TypeSpec.Builder builder = TypeSpec.classBuilder("testClass"); builder.addMethods( - solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder)); + solidityFunctionWrapper.buildEventFunctions( + functionDefinition, + builder, + solidityFunctionWrapper.getDuplicatedEventNames( + Collections.singletonList(functionDefinition)))); String expected = "class testClass {\n" @@ -853,7 +861,11 @@ public void testBuildEventWithNativeList() throws Exception { TypeSpec.Builder builder = TypeSpec.classBuilder("testClass"); builder.addMethods( - solidityFunctionWrapper.buildEventFunctions(functionDefinition, builder)); + solidityFunctionWrapper.buildEventFunctions( + functionDefinition, + builder, + solidityFunctionWrapper.getDuplicatedEventNames( + Collections.singletonList(functionDefinition)))); String expected = "class testClass {\n" @@ -926,6 +938,140 @@ public void testBuildFuncNameConstants() throws Exception { assertEquals(builder.build().toString(), (expected)); } + @Test + public void testBuildFunctionDuplicatedEventNames() throws Exception { + AbiDefinition firstEventDefinition = + new AbiDefinition( + false, + Arrays.asList( + new NamedType("action", "string", false), + new NamedType("pauseState", "bool", false)), + "eventName", + Collections.emptyList(), + "event", + false); + AbiDefinition secondEventDefinition = + new AbiDefinition( + false, + Arrays.asList( + new NamedType("cToken", "address", false), + new NamedType("action", "string", false), + new NamedType("pauseState", "bool", false)), + "eventName", + Collections.emptyList(), + "event", + false); + TypeSpec.Builder builder = TypeSpec.classBuilder("testClass"); + builder.addMethods( + solidityFunctionWrapper.buildFunctionDefinitions( + "testClass", + builder, + Arrays.asList(firstEventDefinition, secondEventDefinition))); + + String expected = + "class testClass {\n" + + " public static final org.web3j.abi.datatypes.Event EVENTNAME1_EVENT = new org.web3j.abi.datatypes.Event(\"eventName\", \n" + + " java.util.Arrays.>asList(new org.web3j.abi.TypeReference() {}, new org.web3j.abi.TypeReference() {}));\n" + + " ;\n" + + "\n" + + " public static final org.web3j.abi.datatypes.Event EVENTNAME_EVENT = new org.web3j.abi.datatypes.Event(\"eventName\", \n" + + " java.util.Arrays.>asList(new org.web3j.abi.TypeReference() {}, new org.web3j.abi.TypeReference() {}, new org.web3j.abi.TypeReference() {}));\n" + + " ;\n" + + "\n" + + " public static java.util.List getEventName1Events(\n" + + " org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {\n" + + " java.util.List valueList = staticExtractEventParametersWithLog(EVENTNAME1_EVENT, transactionReceipt);\n" + + " java.util.ArrayList responses = new java.util.ArrayList(valueList.size());\n" + + " for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {\n" + + " EventName1EventResponse typedResponse = new EventName1EventResponse();\n" + + " typedResponse.log = eventValues.getLog();\n" + + " typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" + + " typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(1).getValue();\n" + + " responses.add(typedResponse);\n" + + " }\n" + + " return responses;\n" + + " }\n" + + "\n" + + " public static EventName1EventResponse getEventName1EventFromLog(\n" + + " org.web3j.protocol.core.methods.response.Log log) {\n" + + " org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EVENTNAME1_EVENT, log);\n" + + " EventName1EventResponse typedResponse = new EventName1EventResponse();\n" + + " typedResponse.log = log;\n" + + " typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" + + " typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(1).getValue();\n" + + " return typedResponse;\n" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventName1EventFlowable(\n" + + " org.web3j.protocol.core.methods.request.EthFilter filter) {\n" + + " return web3j.ethLogFlowable(filter).map(log -> getEventName1EventFromLog(log));\n" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventName1EventFlowable(\n" + + " org.web3j.protocol.core.DefaultBlockParameter startBlock,\n" + + " org.web3j.protocol.core.DefaultBlockParameter endBlock) {\n" + + " org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());\n" + + " filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(EVENTNAME1_EVENT));\n" + + " return eventName1EventFlowable(filter);\n" + + " }\n" + + "\n" + + " public static java.util.List getEventNameEvents(\n" + + " org.web3j.protocol.core.methods.response.TransactionReceipt transactionReceipt) {\n" + + " java.util.List valueList = staticExtractEventParametersWithLog(EVENTNAME_EVENT, transactionReceipt);\n" + + " java.util.ArrayList responses = new java.util.ArrayList(valueList.size());\n" + + " for (org.web3j.tx.Contract.EventValuesWithLog eventValues : valueList) {\n" + + " EventNameEventResponse typedResponse = new EventNameEventResponse();\n" + + " typedResponse.log = eventValues.getLog();\n" + + " typedResponse.cToken = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" + + " typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(1).getValue();\n" + + " typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(2).getValue();\n" + + " responses.add(typedResponse);\n" + + " }\n" + + " return responses;\n" + + " }\n" + + "\n" + + " public static EventNameEventResponse getEventNameEventFromLog(\n" + + " org.web3j.protocol.core.methods.response.Log log) {\n" + + " org.web3j.tx.Contract.EventValuesWithLog eventValues = staticExtractEventParametersWithLog(EVENTNAME_EVENT, log);\n" + + " EventNameEventResponse typedResponse = new EventNameEventResponse();\n" + + " typedResponse.log = log;\n" + + " typedResponse.cToken = (java.lang.String) eventValues.getNonIndexedValues().get(0).getValue();\n" + + " typedResponse.action = (java.lang.String) eventValues.getNonIndexedValues().get(1).getValue();\n" + + " typedResponse.pauseState = (java.lang.Boolean) eventValues.getNonIndexedValues().get(2).getValue();\n" + + " return typedResponse;\n" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventNameEventFlowable(\n" + + " org.web3j.protocol.core.methods.request.EthFilter filter) {\n" + + " return web3j.ethLogFlowable(filter).map(log -> getEventNameEventFromLog(log));\n" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventNameEventFlowable(\n" + + " org.web3j.protocol.core.DefaultBlockParameter startBlock,\n" + + " org.web3j.protocol.core.DefaultBlockParameter endBlock) {\n" + + " org.web3j.protocol.core.methods.request.EthFilter filter = new org.web3j.protocol.core.methods.request.EthFilter(startBlock, endBlock, getContractAddress());\n" + + " filter.addSingleTopic(org.web3j.abi.EventEncoder.encode(EVENTNAME_EVENT));\n" + + " return eventNameEventFlowable(filter);\n" + + " }\n" + + "\n" + + " public static class EventName1EventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {\n" + + " public java.lang.String action;\n" + + "\n" + + " public java.lang.Boolean pauseState;\n" + + " }\n" + + "\n" + + " public static class EventNameEventResponse extends org.web3j.protocol.core.methods.response.BaseEventResponse {\n" + + " public java.lang.String cToken;\n" + + "\n" + + " public java.lang.String action;\n" + + "\n" + + " public java.lang.Boolean pauseState;\n" + + " }\n" + + "}\n"; + + assertEquals(builder.build().toString(), (expected)); + } + @Test public void testBuildFunctionTransactionAndCall() throws Exception { AbiDefinition functionDefinition =