3

How can I create and use Interfaces inside a contract?

For example when I have the following contract:

package com.jelurida.ardor.contracts;

import nxt.addons.AbstractContract;
import nxt.addons.JO;
import nxt.addons.RequestContext;

public class TestContract extends AbstractContract {


    public interface Test {
        String addPrefix(String text);
    }


    public class TestImpl implements Test {
        @Override
        public String addPrefix(String text) {
            return "prefix_" + text;
        }
    }


    @Override
    public JO processRequest(RequestContext context) {
        Test test = new TestImpl();
        JO resp = new JO();
        resp.put("text", test.addPrefix("some text"));
        return context.generateResponse(resp);
    }
}

I get the following error while running unit tests:

2018-12-20 17:40:09 INFO: main Loading resource from com/jelurida/ardor/contracts/TestContract.class
2018-12-20 17:40:09 INFO: main Loading resource from classpath com/jelurida/ardor/contracts/TestContract.class
2018-12-20 17:40:09 INFO: main Loading inner class com.jelurida.ardor.contracts.TestContract.TestImpl resource from com/jelurida/ardor/contracts/TestContract$TestImpl.class
2018-12-20 17:40:09 INFO: main Loading resource from classpath com/jelurida/ardor/contracts/TestContract$TestImpl.class
2018-12-20 17:40:09 INFO: main Loading inner class com.jelurida.ardor.contracts.TestContract.Test resource from com/jelurida/ardor/contracts/TestContract$Test.class
2018-12-20 17:40:09 INFO: main Loading resource from classpath com/jelurida/ardor/contracts/TestContract$Test.class

2018-12-20 17:40:09 INFO: main Shutting down...

java.lang.LinkageError: loader (instance of  nxt/addons/ContractLoader$CloudDataClassLoader): attempted  duplicate class definition for name: "com/jelurida/ardor/contracts/TestContract$Test"

    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at nxt.addons.ContractLoader$CloudDataClassLoader.findClass(ContractLoader.java:308)
    at nxt.addons.ContractLoader.loadContractFromJar(ContractLoader.java:252)
    at nxt.addons.ContractLoader.loadContractFromJar(ContractLoader.java:210)
    at nxt.tools.ContractManager.loadContract(ContractManager.java:437)
    at nxt.tools.ContractManager.uploadImpl(ContractManager.java:327)
    at com.jelurida.ardor.contracts.ContractTestHelper.lambda$deployContract$0(ContractTestHelper.java:110)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.jelurida.ardor.contracts.ContractTestHelper.deployContract(ContractTestHelper.java:107)
    at com.jelurida.ardor.contracts.ContractTestHelper.deployContract(ContractTestHelper.java:98)
    at com.jelurida.ardor.contracts.ContractTestHelper.deployContract(ContractTestHelper.java:93)
    at com.jelurida.ardor.contracts.ContractTestHelper.deployContract(ContractTestHelper.java:89)
    at com.jelurida.ardor.contracts.TestContractTest.uploadTest(TestContractTest.java:9)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runners.Suite.runChild(Suite.java:127)
    at org.junit.runners.Suite.runChild(Suite.java:26)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

How can I solve this error? I'm using version 2.2.1

2

I assume that the problem here is that Test interface is being loaded twice, first when the contract is being scanned for inner classes to load then indirectly when the TestImpl class is loaded and this is causing the "attempted duplicate class definition for name: "com/jelurida/ardor/contracts/TestContract$Test" error.

It is probably something we can fix for the next release.

  • 1
    That would be really really nice and helpful. FYI the same error occurs when you move the Test interface and TestImpl class from inner classes to "normal" classes where everyone has their own file – atzen Dec 23 '18 at 12:44
  • 1
    In the next release we'll simply prevent a class from being loaded twice by the cloud data class loader. – lyaffe Dec 24 '18 at 7:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.