Класс Kotlin должен иметь единственный конструктор без аргументов - PullRequest
0 голосов
/ 13 декабря 2018

Я создаю экземпляр своего объекта, используя:

val payInCurrency = Currency::class.createInstance()
            .copy(code = "GBP")

, но в этой строке получаю исключение:

java.lang.IllegalArgumentException: Class should have a single no-arg constructor: class com.abc.Currency
    at kotlin.reflect.full.KClasses.createInstance(KClasses.kt:281)
    at com.abc.MyInteractorTest.setUp(MyInteractorTest.kt:55)
    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:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:79)
    at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:85)
    at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
    at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:163)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:106)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:66)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:117)
    at sun.reflect.GeneratedMethodAccessor34.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:155)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:137)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
    at java.lang.Thread.run(Thread.java:748)

Ответы [ 3 ]

0 голосов
/ 13 декабря 2018

Вы вызываете createInstance(), и документация для этого метода говорит:

Создает новый экземпляр класса, вызывая конструктор, у которого нет параметров.или все параметры которого являются необязательными (см. KParameter.isOptional).Если таких конструкторов нет или их много, выдается исключение.

Вы вызываете createInstance для класса, и он выдает указанное исключение, либо класс:

  • не имеет конструктора без параметров (или где все параметры являются необязательными)
  • имеет несколько конструкторов, соответствующих этому определению
0 голосов
/ 15 декабря 2018

Извините за путаницу и спасибо за помощь.
Действительно, очевидно, что KClasses.createInstance() требует, чтобы у классов был "конструктор без аргументов".

Итак, 1 решение - изменить мои классы, чтобы ввести «конструктор без аргументов».

Другое решение - использовать мой собственный createInstance(), который принимает классы без "конструктора без аргументов".Оказалось, у моей команды уже есть свои createInstance(), и я использовал неправильный метод (KClasses.createInstance())

0 голосов
/ 13 декабря 2018

Либо убедитесь, что data class инициализирует все значения (поэтому будет доступен конструктор по умолчанию), либо предоставьте соответствующий конструктор по умолчанию самостоятельно:

// setting default values on all properties:
data class Currency(val code : String = "GBP" / * all other properties need to have a default value assigned too */)

// or add a default constructor:
data class Currency(val code : String /* other properties */) {
  constructor() : this("GBP" /* other properties default values */)
}

Обратите внимание, что createInstance использует singleOrNull внутри и выдает исключение, если существует более 1 (или ни одного) конструктора, удовлетворяющего критериям наличия тольконеобязательные параметры.Поэтому, если у вас есть несколько таких конструкторов или вы не хотите изменять Currency -класс, затем итерируйте по доступным конструкторам, используйте тот, который подходит, и заполните параметры.Тогда вы, вероятно, даже можете пропустить этот copy -all.

Почему вы даже используете этот подход для копирования данных?copy имеет смысл только в том случае, если уже есть объект, для которого вы хотите изменить только некоторые свойства, но в остальном оставить все как есть, и ваш пример, вероятно, можно записать просто:

val payInCurrency = Currency(code = "GBP")

Вы уже знаете, что хотите Currency, и вы также знаете, что хотите, чтобы код был "GBP".

...