diff --git a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java index a4d20b73d..acefa0d92 100644 --- a/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java +++ b/codegen/src/main/java/org/web3j/codegen/SolidityFunctionWrapper.java @@ -402,9 +402,19 @@ private 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) @@ -416,13 +426,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)) { @@ -430,12 +441,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); @@ -1814,7 +1848,9 @@ MethodSpec buildEventTransactionReceiptFunction( } List buildEventFunctions( - AbiDefinition functionDefinition, TypeSpec.Builder classBuilder) + AbiDefinition functionDefinition, + TypeSpec.Builder classBuilder, + Map eventsCount) throws ClassNotFoundException { String functionName = functionDefinition.getName(); List inputs = functionDefinition.getInputs(); @@ -1843,7 +1879,10 @@ List buildEventFunctions( parameters.add(parameter); } - classBuilder.addField(createEventDefinition(functionName, parameters)); + classBuilder.addField( + createEventDefinition(functionName, parameters, eventsCount, functionDefinition)); + + functionName = functionDefinition.getName(); 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 257a51f04..1426f582f 100644 --- a/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java +++ b/codegen/src/test/java/org/web3j/codegen/SolidityFunctionWrapperTest.java @@ -673,7 +673,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" @@ -757,7 +761,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" @@ -833,7 +841,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" @@ -902,6 +914,133 @@ 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(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" + + " EventNameEventResponse typedResponse = new EventNameEventResponse();\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 io.reactivex.Flowable eventName1EventFlowable(org.web3j.protocol.core.methods.request.EthFilter filter) {\n" + + " return web3j.ethLogFlowable(filter).map(new io.reactivex.functions.Function() {\n" + + " @java.lang.Override\n" + + " public EventNameEventResponse apply(org.web3j.protocol.core.methods.response.Log log) {\n" + + " org.web3j.tx.Contract.EventValuesWithLog eventValues = extractEventParametersWithLog(EVENTNAME1_EVENT, log);\n" + + " EventNameEventResponse typedResponse = new EventNameEventResponse();\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" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventName1EventFlowable(org.web3j.protocol.core.DefaultBlockParameter startBlock, 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(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 io.reactivex.Flowable eventNameEventFlowable(org.web3j.protocol.core.methods.request.EthFilter filter) {\n" + + " return web3j.ethLogFlowable(filter).map(new io.reactivex.functions.Function() {\n" + + " @java.lang.Override\n" + + " public EventNameEventResponse apply(org.web3j.protocol.core.methods.response.Log log) {\n" + + " org.web3j.tx.Contract.EventValuesWithLog eventValues = extractEventParametersWithLog(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" + + " }\n" + + "\n" + + " public io.reactivex.Flowable eventNameEventFlowable(org.web3j.protocol.core.DefaultBlockParameter startBlock, 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 EventNameEventResponse 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 =