Kotlin + SpringBoot 2.0.0-M4 tu load application context(BeanCreationException)

时间:2017-09-18 11:16:18

标签: spring spring-boot mockito kotlin

我正在与Kotlin和Spring合作(通过SpringBoot)。 我在2.0.0-M3上,一切都很正确。

我决定跳到M4。然后,我遇到了一些麻烦。

我得到了以下堆栈跟踪:

java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
    at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:107)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
    at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
    at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
    at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:242)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    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.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    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)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jpaMappingContext': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.reflect.jvm.ReflectJvmMapping.getJavaConstructor, parameter $receiver
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1702)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:583)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:740)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:750)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:386)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
    at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:138)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:99)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:117)
    ... 25 more
Caused by: java.lang.IllegalArgumentException: Parameter specified as non-null is null: method kotlin.reflect.jvm.ReflectJvmMapping.getJavaConstructor, parameter $receiver
    at kotlin.reflect.jvm.ReflectJvmMapping.getJavaConstructor(ReflectJvmMapping.kt)
    at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers$2.lambda$discover$2(PreferredConstructorDiscoverer.java:169)
    at java.util.Optional.orElseGet(Optional.java:267)
    at org.springframework.data.mapping.model.PreferredConstructorDiscoverer$Discoverers$2.discover(PreferredConstructorDiscoverer.java:165)
    at org.springframework.data.mapping.model.PreferredConstructorDiscoverer.discover(PreferredConstructorDiscoverer.java:77)
    at org.springframework.data.mapping.model.BasicPersistentEntity.<init>(BasicPersistentEntity.java:93)
    at org.springframework.data.jpa.mapping.JpaPersistentEntityImpl.<init>(JpaPersistentEntityImpl.java:54)
    at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.createPersistentEntity(JpaMetamodelMappingContext.java:66)
    at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.createPersistentEntity(JpaMetamodelMappingContext.java:40)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:376)
    at org.springframework.data.mapping.context.AbstractMappingContext.addPersistentEntity(AbstractMappingContext.java:343)
    at java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.data.mapping.context.AbstractMappingContext.initialize(AbstractMappingContext.java:469)
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:90)
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:43)
    at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:141)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1761)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1698)
    ... 40 more

这是我的代码:

实体

@Entity
@Table(name = "code_list")
class CodeList : Serializable {
    /* ----- FIELDS ----- */
    //endregion


    //region GET / SET methods
    @Id
    @Column(name = "NO_SECSOC", nullable = false)
    var secSocId: Long? = null
    @Id
    @Column(name = "ID_CODE_LIST")
    var codelistId: String? = null
    @Id
    @Column(name = "NO_COM_PARITAIRE")
    var comParitaireId: String? = null
    @Id
    @Column(name = "NO_EMPLOYEUR")
    var employerId: Long? = null
    @Id
    @Column(name = "NO_CCTE")
    var ccteId: String? = null
    @Id
    @Column(name = "VAL_NUM")
    var numberValue: Long? = null
    @Id
    @Column(name = "VAL_STRING")
    var stringValue: String? = null

    @Column(name = "DT_DEBUT_EFFET")
    var startEffectDate: LocalDate? = null

    @Column(name = "DT_FIN_EFFET")
    var endEffectDate: LocalDate? = null

    @Embedded
    var label: MultilingualString? = null

    /** Set the type of value to use  */
    @ManyToOne(optional = true, fetch = FetchType.LAZY)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "ID_CODE_LIST", insertable = false, updatable = false)
    var codeListType: CodeListType? = null

    //region Constructor
    constructor() {}

    constructor(secSocId: Long?, employerId: Long?, ccteId: String, codeListId: String) {
        this.secSocId = secSocId
        this.employerId = employerId
        this.ccteId = ccteId
        this.codelistId = codeListId
    }
    //endregion

}

存储库

@Component
class CodeListRepository {

    @Autowired
    lateinit var entityManager: EntityManager

    fun findCodeListLikeCB(predicateMap: Map<String, Any?>): List<CodeList> {

        val cb = entityManager.criteriaBuilder

        val query = cb.createQuery(CodeList::class.java)

        val codeListRoot = query.from(CodeList::class.java)

        val predicateList: ArrayList<Predicate> = ArrayList()

        // foreach to build predicateList
        for ((key, value) in predicateMap) {
            if (value != null) {
                // For a list, needed to add a condition IN
                if (value is List<*>)
                    predicateList.add(codeListRoot.get<Any>(key).`in`(value))

                //For a date, needed to add condition
                //  For start date --> before param start date
                //  For end date   --> after param date or null
                if (value is LocalDate) {
                    if (key == "startEffectDate") {
                        predicateList.add(cb.lessThanOrEqualTo(codeListRoot.get("startEffectDate"), value))
                    }
                    if (key == "endEffectDate") {
                        // cb.conjunction allow to add parenthesis to the predicate
                        val predicate = cb.conjunction()
                        predicate.expressions.add(cb.or(cb.greaterThan(codeListRoot.get("endEffectDate"), value), cb.isNull(codeListRoot.get<Any>("endEffectDate"))))
                        predicateList.add(predicate)
                    }
                }
                if (value !is LocalDate && value !is List<*>) {
                    predicateList.add(cb.equal(codeListRoot.get<Any>(key), value))
                }
            }
        }

        query.select(codeListRoot).where(cb.and(*predicateList.toTypedArray()))

        return entityManager.createQuery(query).resultList
    }

}

测试课

@ComponentScan("be.groups")
@EntityScan("be.groups")
@EnableJpaRepositories(basePackages = arrayOf("be.groups"))
@SpringBootTest(classes = arrayOf(DatabaseComponent::class))
@RunWith(SpringJUnit4ClassRunner::class)
class CodeListRepositoryTest {

    @Autowired
    lateinit var repository: CodeListRepository

    @Test
    fun findCodeListLikeCB() {
        val codeLists = repository.findCodeListLikeCB(mapOf("codelistId" to "CANAL"))
        assertNotNull(codeLists)
        assertFalse(codeLists.isEmpty())

        val codeList = repository.findCodeListLikeCB(mapOf("codelistId" to "CANAL", "numberValue" to 0))
        assertNotNull(codeList)
        assertFalse(codeList.isEmpty())
        assertEquals(codeList.size, 1)
        assertEquals(codeList[0].codelistId, "CANAL")
        assertEquals(codeList[0].numberValue, 0)
    }

}

测试配置(mockito-extensions / org.mockito.plugins.MockMaker)

mock-maker-inline

关于自2.0.0-M3以来出了什么问题的任何想法?

4 个答案:

答案 0 :(得分:0)

有同样的问题。 删除除默认no-arg构造函数之外的所有Entity类构造函数。解决问题

答案 1 :(得分:0)

自2.0.0-M5以来已修复

答案 2 :(得分:0)

你可以找到有用的kotlin编译器插件。对于这种情况(或类似),我建议使用jpa compiler plugin。它将在后台生成默认的no-args构造函数,用于自动注释@Entity,@ Embeddable和@MappedSuperclass的类,这将允许kotlin反射api正确创建和填充示例实体,而无需将每个单独的字段作为可选项提供。

答案 3 :(得分:0)

我添加了kotlin-reflect依赖性,这对我有用。

<dependency>
    <groupId>org.jetbrains.kotlin</groupId>
    <artifactId>kotlin-reflect</artifactId>
</dependency>
相关问题