Spring boot and Spock integration test - spring

I am new to Spring boot and while testing the REST endpoint using SPOCK , came across with the question #24405727
I have tried the exact configuration but getting the below exception
java.lang.IllegalStateException: The WebApplicationContext for test context [TestContext#21a722ef testClass = HelloControllerSpec, testInstance = com.hello.HelloControllerSpec#63e68a2b, testMethod = [null], testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration#3479404a testClass = HelloControllerSpec, locations = '{}', classes = '{class com.Application}', contextInitializerClasses = '[]', activeProfiles = '{}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.boot.test.SpringApplicationContextLoader', parent = [null]]] must be configured with a MockServletContext.
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:111)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:74)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
at org.spockframework.spring.SpringTestContextManager.prepareTestInstance(SpringTestContextManager.java:49)
at org.spockframework.spring.SpringInterceptor.interceptSetupMethod(SpringInterceptor.java:42)
at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:28)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:84)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.spockframework.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:138)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.runTestClass(JUnitTestClassExecuter.java:86)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecuter.execute(JUnitTestClassExecuter.java:49)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassProcessor.processTestClass(JUnitTestClassProcessor.java:69)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:48)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.messaging.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:105)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:355)
at org.gradle.internal.concurrent.DefaultExecutorFactory$StoppableExecutorImpl$1.run(DefaultExecutorFactory.java:64)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Below is my Groovy spock specification
#ContextConfiguration(loader = SpringApplicationContextLoader.class, classes = Application.class)
#WebAppConfiguration
#IntegrationTest
class HelloControllerSpec extends Specification {
def "Greeting test"() {
when:
ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:8080", String.class);
then:
entity.statusCode == HttpStatus.OK
}
}
Any help is highly appreciated.

Related

Can't configure EntityManager with Transactional using Spring Boot

Currently I am writing Spring boot application to move data from Database in source A to another Database in source B. To do so, I am trying to configure Spring with two datasource and tried to retrive data from source A concurrently and insert to source B. I could retrieve data from source A but the problem is that I could not insert those data to source B. It seems like I didn't configure transactional correctly with EntityManager. Please check my below code and help me figure out this.
Here is my datasource configuration class:
#Configuration
#EnableJpaRepositories(
basePackages = ["com.gdce.xgen.repo.psql"],
entityManagerFactoryRef = "psqlEntityManager",
transactionManagerRef = "psqlTransactional")
#EnableTransactionManagement
#ComponentScan("com.gdce.xgen.repo.psql")
class PsqlDataSource {
#Bean("psqlEntityManager")
fun entityManagerFactory(#Qualifier("psqlDataSource1") dataSource: DataSource): LocalContainerEntityManagerFactoryBean {
val em = LocalContainerEntityManagerFactoryBean()
val vendorAdapter: JpaVendorAdapter = HibernateJpaVendorAdapter()
em.dataSource = dataSource
em.jpaVendorAdapter = vendorAdapter
em.setPackagesToScan("com.gdce.xgen.model.psql")
em.setJpaProperties(hibernateProperties())
return em
}
#Bean("psqlDataSource1")
#ConfigurationProperties("psql.datasource.main.configuration")
fun dataSource(#Qualifier("psqlDataSourceProperties") dataSourceProperties: DataSourceProperties): DataSource {
return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource::class.java).build()
}
#Bean("psqlDataSourceProperties")
#ConfigurationProperties("psql.datasource.main")
fun dataSourceProperties(): DataSourceProperties {
return DataSourceProperties()
}
#Bean("psqlTransactional")
fun transactionManager(#Qualifier("psqlEntityManager") entityManager: EntityManager, #Qualifier("psqlDataSource1") dataSource: DataSource): PlatformTransactionManager {
val transactionManager = JpaTransactionManager(entityManager.entityManagerFactory)
transactionManager.dataSource = dataSource
return transactionManager
}
private fun hibernateProperties(): Properties {
val hibernateProperties = Properties()
hibernateProperties.setProperty("hibernate.jdbc.lob.non_contextual_creation", "true")
hibernateProperties.setProperty("hibernate.show_sql", "true")
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", "update")
hibernateProperties.setProperty("hibernate.jdbc.batch_size", "40000")
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect")
hibernateProperties.setProperty("hibernate.connection.pool_size", "20")
hibernateProperties.setProperty("hibernate.order_inserts", "true")
hibernateProperties.setProperty("hibernate.order_updates", "true")
// hibernateProperties.setProperty("hibernate.format_sql", "true")
return hibernateProperties
}
}
Here is the class I use to insert data into destination data source
#Service
class InsertRepo {
#Qualifier("psqlEntityManager")
// #Autowired // also tried this but not working and saw many people use #PersistenceContext and tried it too
#PersistenceContext
private lateinit var entityManager: EntityManager
fun migrate(records: ArrayList<Any>) {
records.parallelStream().forEach { record ->
run {
entityManager.persist(record)
}
}
}
}
Here an error output:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy83.persist(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo$migrate$1.accept(InsertRepo.kt:18)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:408)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:16)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
If i modify my InsertRepo to:
#Service
class InsertRepo {
#Qualifier("psqlEntityManager")
#PersistenceContext
private lateinit var entityManager: EntityManager
#javax.transaction.Transactional
fun migrate(records: ArrayList<Any>) {
records.parallelStream().forEach { record ->
run {
entityManager.persist(record)
}
}
}
}
Then I got this error log:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:18)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$85ac330b.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
I have also tried to use #org.springframework.transaction.annotation.Transactional then i got this error log:
Exception in thread "DefaultDispatcher-worker-1" javax.persistence.TransactionRequiredException
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:603)
at java.base/java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:678)
at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:737)
at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:661)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:17)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$82673045.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)
Caused by: javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:298)
at com.sun.proxy.$Proxy83.persist(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo$migrate$1.accept(InsertRepo.kt:19)
at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
I have tried to get transactional from entityManager but i got some error:
Exception in thread "DefaultDispatcher-worker-1" java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:264)
at com.sun.proxy.$Proxy83.getTransaction(Unknown Source)
at com.gdce.xgen.repo.psql.InsertRepo.migrate(InsertRepo.kt:17)
at com.gdce.xgen.repo.psql.InsertRepo$$FastClassBySpringCGLIB$$aa68e733.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:769)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:353)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:99)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.gdce.xgen.repo.psql.InsertRepo$$EnhancerBySpringCGLIB$$3c37a126.migrate(<generated>)
at com.gdce.xgen.controller.TestController$find$$inlined$map$lambda$1.invokeSuspend(TestController.kt:46)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)

What's wrong with coroutine context?

I'am trying to use new Spring 5.2 feature - integration with kotlin coroutines, but in runtime I always has an NPE. This is example:
#RestController
class SomeController() {
val webClient = WebClient.builder()
.baseUrl("https://www.google.com")
.build()
#GetMapping
suspend fun get(): String? {
return webClient
.get()
.awaitExchange()
.awaitBody()
}
}
and NPE on .awaitExchange():
kotlin.KotlinNullPointerException: null
at kotlin.coroutines.jvm.internal.ContinuationImpl.getContext(ContinuationImpl.kt:105) ~[kotlin-stdlib-1.3.40.jar:1.3.40-release-123 (1.3.40)]
at kotlin.coroutines.jvm.internal.ContinuationImpl.<init>(ContinuationImpl.kt:102) ~[kotlin-stdlib-1.3.40.jar:1.3.40-release-123 (1.3.40)]
at org.springframework.web.reactive.function.client.WebClientExtensionsKt$awaitExchange$1.<init>(WebClientExtensions.kt) ~[spring-webflux-5.2.0.M3.jar:5.2.0.M3]
at org.springframework.web.reactive.function.client.WebClientExtensionsKt.awaitExchange(WebClientExtensions.kt) ~[spring-webflux-5.2.0.M3.jar:5.2.0.M3]
at com.test.SomeController.get$suspendImpl(SomeController.kt:22) ~[classes/:na]
at com.test.SomeController.get(SomeController.kt) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.web.reactive.result.method.InvocableHandlerMethod.lambda$invoke$0(InvocableHandlerMethod.java:146) ~[spring-webflux-5.2.0.M3.jar:5.2.0.M3]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118) [reactor-core-3.3.0.M2.jar:3.3.0.M2]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1575) ~[reactor-core-3.3.0.M2.jar:3.3.0.M2]
...
Any ideas what I'am doing wrong?
P.s. gradle dependencies:
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version = "1.2.2")
implementation(group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-reactor", version = "1.2.2")
implementation(group = "org.springframework.boot", name = "spring-boot-starter-webflux", version = "2.2.0.M4")
}
Thanks!

How to launch sql-script before integration tests?

There is application on spring+oracle.
So, I need to create sql-before script for cleaning base before integration tests.
So, my IT looks like this
#Category(Integrations.class)
#WebAppConfiguration
#RunWith(SpringRunner.class)
#TestPropertySource("classpath:application-${envConfig}.properties")
#ContextConfiguration(classes = {IntegrationConfig.class}, loader = AnnotationConfigWebContextLoader.class)
#Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, scripts = "classpath:before.sql")
public class ControllerTest {
#Value("${server.remote}")
private String remote;
#Value("${app.name}")
private String appName;
private final String HTTP = "http://";
protected RestTemplate restTemplate = new RestTemplate();
#Value("${server.port}")
protected int port;
#Value("${server.address}")
protected String serverAddress;
#Test
public void test(){
}
envConfig - is an envirenment variable from jv.
in test->resources located file named before.sql with my script.
There is error message when try to launch this test:
at org.springframework.util.Assert.state(Assert.java:94)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:203)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:142)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.afterTestMethod(SqlScriptsTestExecutionListener.java:121)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:443)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:94)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
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.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.04 sec <<< FAILURE!
test(integration.ControllerTest) Time elapsed: 0.016 sec <<< ERROR!
java.lang.IllegalStateException: Failed to execute SQL scripts for test context [DefaultTestContext#16a0ee18 testClass = ControllerTest, testInstance = integration.RiskMet
ricControllerTest#3d6f0054, testMethod = test#ControllerTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration#505fc5a4 testClass = Risk
MetricControllerTest, locations = '{}', classes = '{class integration.config.IntegrationConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations =
'{classpath:application-${envConfig}.properties}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], resourceBasePath = 'src/main/webapp', contextLoader = 'org.spr
ingframework.test.context.web.AnnotationConfigWebContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.populatedReque
stContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]: supply at least a DataSource or PlatformTransactio
nManager.
at org.springframework.util.Assert.state(Assert.java:94)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:203)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.executeSqlScripts(SqlScriptsTestExecutionListener.java:142)
at org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener.afterTestMethod(SqlScriptsTestExecutionListener.java:121)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:443)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:94)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
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.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:27)
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.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at org.apache.maven.surefire.junitcore.JUnitCoreWrapper.execute(JUnitCoreWrapper.java:62)
at org.apache.maven.surefire.junitcore.JUnitCoreProvider.invoke(JUnitCoreProvider.java:139)
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.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
Results :
Tests in error:
test(integration.ControllerTest): Failed to execute SQL scripts for test context [DefaultTestContext#16a0ee18 testClass = ControllerTest, testInstance = integr
ation.ControllerTest#3d6f0054, testMethod = test#ControllerTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration#505fc5a4 tes
tClass = ControllerTest, locations = '{}', classes = '{class integration.config.IntegrationConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourc
eLocations = '{classpath:application-${envConfig}.properties}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], resourceBasePath = 'src/main/webapp', contextLoad
er = 'org.springframework.test.context.web.AnnotationConfigWebContextLoader', parent = [null]], attributes = map['org.springframework.test.context.web.ServletTestExecutionListener.p
opulatedRequestContextHolder' -> true, 'org.springframework.test.context.web.ServletTestExecutionListener.resetRequestContextHolder' -> true]]: supply at least a DataSource or Platf
ormTransactionManager.
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
You can use libraries like flyway or DbUnit.
In our project, we had a custom gradle plugin that sets up the flyway scripts just before test task runs.
In your case it can be simple as this flyway-test-extension. Yes, you have to know about flyway but it's as easy as a 1 hour read at max.
https://github.com/flyway/flyway-test-extensions
So the idea for flyway test is this:
Mention the test scripts in a location under tests
Use #FlywayTest on top of you unit test methods like #Before and #After

ManyToOne not mapped with the parent ID

I am trying to implement tests in my spring boot app, but I have problems with ManyToOne/OneToMany links.
It seems that the link from the subobject is not created, while I use CascadeType = ALL.
I tried creating it in the BusinesDomain.addSubdomain, adding "subDomain.domain(this);" but this causes a loop.
I found out other topics with the same error but non of them seem to cover my issue.
Could you please help me find out what seems to be the issue ?
Thanks a lot!
Here are my Entities
import lombok.AccessLevel;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
import lombok.experimental.Accessors;
#Accessors(fluent = true)
#Data
#Entity
#NoArgsConstructor
public class BusinessDomain {
#Setter(AccessLevel.NONE)
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#NonNull
#Column(unique=true)
private String name;
#OneToMany(mappedBy = "domain", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<BusinessSubDomain> subDomains = new LinkedHashSet<>();
public void addSubDomain(BusinessSubDomain subDomain) {
subDomains.add(subDomain);
}
}
#Accessors(fluent = true)
#Data
#Entity
#NoArgsConstructor
public class BusinessSubDomain {
#Setter(AccessLevel.NONE)
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
#ManyToOne(optional = false)
#JoinColumn(name = "business_domain_id", referencedColumnName="id")
private BusinessDomain domain;
}
My service class:
#Override
public BusinessDomain saveOrUpdate(BusinessDomain businessDomain) throws OrcaException {
try {
BusinessDomain domain = businessDomainRepository.findByName(businessDomain.name());
if(null == domain) {
// Repository class not overriden (extends CrudRepository<BusinessDomain, Long>)
return businessDomainRepository.save(businessDomain);
} else {
domain.description(businessDomain.description());
domain.subDomains(businessDomain.subDomains());
return businessDomainRepository.save(domain);
}
} catch (Exception e) {
throw new OrcaException(e);
}
}
And my Test:
#RunWith(SpringRunner.class)
#SpringBootTest
public class BusinessDomainTest {
#Test
#Transactional
public void createBusinessDomainWithSubDomain() throws OrcaException {
BusinessDomain passengerBusinessDomain = new BusinessDomain().name(DOMAIN_NAME).description(DOMAIN_DESCRIPTION);
BusinessSubDomain distributionBusinessSubDomain = new BusinessSubDomain().name(SUBDOMAIN_NAME)
.description(SUBDOMAIN_DESCRIPTION);
passengerBusinessDomain.addSubDomain(distributionBusinessSubDomain);
businessDomainService.saveOrUpdate(passengerBusinessDomain);
BusinessDomain domain = businessDomainService.findByName(DOMAIN_NAME);
}
}
With this I get the error message:
[main] INFO
com.myproject.project.test.model.soadatamodel.business.domaining.BusinessDomainTest
- Started BusinessDomainTest in 24.161 seconds (JVM running for 26.159) [main] INFO org.springframework.test.context.transaction.TransactionContext -
Began transaction (1) for test context [DefaultTestContext#76480730
testClass = BusinessDomainTest, testInstance =
com.myproject.project.test.model.soadatamodel.business.domaining.BusinessDomainTest#405a296e,
testMethod = createBusinessDomainWithArea#BusinessDomainTest,
testException = [null], mergedContextConfiguration =
[WebMergedContextConfiguration#5f5c2451 testClass =
BusinessDomainTest, locations = '{}', classes = '{class
com.myproject.project.TestApplication}', contextInitializerClasses =
'[]', activeProfiles = '{}', propertySourceLocations = '{}',
propertySourceProperties =
'{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}',
contextCustomizers =
set[org.springframework.boot.test.context.SpringBootTestContextCustomizer#6eceb130,
org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer#47db50c5,
org.springframework.boot.test.mock.mockito.MockitoContextCustomizer#0,
org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer#0,
org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer#68ceda24],
resourceBasePath = 'src/main/webapp', contextLoader =
'org.springframework.boot.test.context.SpringBootContextLoader',
parent = [null]]]; transaction manager
[org.springframework.orm.jpa.JpaTransactionManager#28d97205]; rollback
[true] [main] INFO
org.hibernate.hql.internal.QueryTranslatorFactoryInitiator -
HHH000397: Using ASTQueryTranslatorFactory Hibernate: select
businessdo0_.id as id1_1_, businessdo0_.description as descript2_1_,
businessdo0_.name as name3_1_ from BusinessDomain businessdo0_ where
businessdo0_.name=? Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence [main] WARN
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - SQL Error: 23502,
SQLState: 23502 [main] ERROR
org.hibernate.engine.jdbc.spi.SqlExceptionHelper - NULL not allowed
for column "BUSINESS_DOMAIN_ID"; SQL statement: insert into
BusinessSubDomain (description, business_domain_id, name, id) values
(?, ?, ?, ?) [23502-168] [main] INFO
org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl -
HHH000010: On release of batch it still contained JDBC statements
org.springframework.dao.DataIntegrityViolationException: could not
execute statement; SQL [n/a]; constraint [null]; nested exception is
org.hibernate.exception.ConstraintViolationException: could not
execute statement at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:278)
at
org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:244)
at
org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:488)
at
org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at
org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy134.findByName(Unknown Source) at
com.myproject.project.service.soadatamodel.business.domaining.impl.BusinessDomainServiceImpl.findByName(BusinessDomainServiceImpl.java:40)
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:483) at
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy137.findByName(Unknown Source) at
com.myproject.project.test.model.soadatamodel.business.domaining.BusinessDomainTest.createBusinessDomainWithArea(BusinessDomainTest.java:82)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)Hibernate:
call next value for hibernate_sequence Hibernate: insert into
BusinessDomain (description, name, id) values (?, ?, ?) Hibernate:
insert into BusinessSubDomain (description, business_domain_id, name,
id) values (?, ?, ?, ?) could not execute statement; SQL [n/a];
constraint [null]; nested exception is
org.hibernate.exception.ConstraintViolationException: could not
execute statement
org.springframework.dao.DataIntegrityViolationException: could not
execute statement; SQL [n/a]; constraint [null]; nested exception is
org.hibernate.exception.ConstraintViolationException: could not
execute statement
at java.lang.reflect.Method.invoke(Method.java:483) 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.InvokeMethod.evaluate(InvokeMethod.java:17)
at
org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at
org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at
org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20) at
org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at
org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
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:191)
at
org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:283)
at
org.apache.maven.surefire.junit4.JUnit4Provider.executeWithRerun(JUnit4Provider.java:173)
at
org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:153)
at
org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:128)
at
org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:203)
at
org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:155)
at
org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:103)
Caused by: org.hibernate.exception.ConstraintViolationException: could
not execute statement at
org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:112)
at
org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:207)
at
org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2949)
at
org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3449)
at
org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:89)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:582)
at
org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:456)
at
org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:337)
at
org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:50)
at
org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1251)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1319) at
org.hibernate.internal.QueryImpl.list(QueryImpl.java:87) at
org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606) at
org.hibernate.jpa.internal.QueryImpl.getSingleResult(QueryImpl.java:529)
at
org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getSingleResult(CriteriaQueryTypeQueryAdapter.java:54)
at
org.springframework.data.jpa.repository.query.JpaQueryExecution$SingleEntityExecution.doExecute(JpaQueryExecution.java:206)
at
org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:85)
at
org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:116)
at
org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:106)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:483)
at
org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:461)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at
org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 56 more Caused by: org.h2.jdbc.JdbcSQLException: NULL not allowed
for column "BUSINESS_DOMAIN_ID"; SQL statement: insert into
BusinessSubDomain (description, business_domain_id, name, id) values
(?, ?, ?, ?) [23502-168] at
org.h2.message.DbException.getJdbcSQLException(DbException.java:329)
at org.h2.message.DbException.get(DbException.java:169) at
org.h2.message.DbException.get(DbException.java:146) at
org.h2.table.Column.validateConvertUpdateSequence(Column.java:293) at
org.h2.table.Table.validateConvertUpdateSequence(Table.java:689) at
org.h2.command.dml.Insert.insertRows(Insert.java:120) at
org.h2.command.dml.Insert.update(Insert.java:84) at
org.h2.command.CommandContainer.update(CommandContainer.java:75) at
org.h2.command.Command.executeUpdate(Command.java:230) at
org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:156)
at
org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:142)
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:483) at
org.apache.tomcat.jdbc.pool.StatementFacade$StatementProxy.invoke(StatementFacade.java:114)
at com.sun.proxy.$Proxy130.executeUpdate(Unknown Source) at
org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:204)
... 84 more [main] INFO
org.springframework.test.context.transaction.TransactionContext -
Rolled back transaction for test context [DefaultTestContext#76480730
testClass = BusinessDomainTest, testInstance =
com.myproject.project.test.model.soadatamodel.business.domaining.BusinessDomainTest#405a296e,
testMethod = createBusinessDomainWithArea#BusinessDomainTest,
testException = [ERROR CODE : UNKNWN001] Unknown Error [Exception
:org.springframework.dao.DataIntegrityViolationException: could not
execute statement; SQL [n/a]; constraint [null]; nested exception is
org.hibernate.exception.ConstraintViolationException: could not
execute statement], mergedContextConfiguration =
[WebMergedContextConfiguration#5f5c2451 testClass =
BusinessDomainTest, locations = '{}', classes = '{class
com.myproject.project.TestApplication}', contextInitializerClasses =
'[]', activeProfiles = '{}', propertySourceLocations = '{}',
propertySourceProperties =
'{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}',
contextCustomizers =
set[org.springframework.boot.test.context.SpringBootTestContextCustomizer#6eceb130,
org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer#47db50c5,
org.springframework.boot.test.mock.mockito.MockitoContextCustomizer#0,
org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer#0,
org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer#68ceda24],
resourceBasePath = 'src/main/webapp', contextLoader =
'org.springframework.boot.test.context.SpringBootContextLoader',
parent = [null]]]. [main] INFO
org.springframework.test.context.transaction.TransactionContext -
Began transaction (1) for test context [DefaultTestContext#76480730
testClass = BusinessDomainTest, testInstance =
com.myproject.project.test.model.soadatamodel.business.domaining.BusinessDomainTest#685e8e17,
testMethod = createSimpleBusinessDomain#BusinessDomainTest,
testException = [null], mergedContextConfiguration =
[WebMergedContextConfiguration#5f5c2451 testClass =
BusinessDomainTest, locations = '{}', classes = '{class
com.myproject.project.TestApplication}', contextInitializerClasses =
'[]', activeProfiles = '{}', propertySourceLocations = '{}',
propertySourceProperties =
'{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}',
contextCustomizers =
set[org.springframework.boot.test.context.SpringBootTestContextCustomizer#6eceb130,
org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer#47db50c5,
org.springframework.boot.test.mock.mockito.MockitoContextCustomizer#0,
org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer#0,
org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer#68ceda24],
resourceBasePath = 'src/main/webapp', contextLoader =
'org.springframework.boot.test.context.SpringBootContextLoader',
parent = [null]]]; transaction manager
[org.springframework.orm.jpa.JpaTransactionManager#28d97205]; rollback
[true]
Finally I understood.
First, the entity adder must be
public void addSubDomain(BusinessSubDomain subDomain) {
subDomains.add(subDomain);
subDomain.domain(this);
}
But this was causing an infinite loop with an infinite call to hash method.
I solved this (caused by lombok) using #Getter and #Setter instead of #Data in my entity.
Thanks

Spring Data JPA custom query with entity as a parameter doesn't work

When I use custom query with entity as parameter in Spring Data JPA I get the exception:
java.sql.SQLException: No value specified for parameter 1
Here are related entities. I have two entities with #OneToOne relationship, like below:
Car:
#Entity
#Table(name = "car")
public class Car {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "car_id")
private long id;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id", unique = true, nullable = true, insertable = true, updatable = true)
private Order order;
...
}
Order:
#Entity
#Table(name = "order")
public class Order {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "order_id")
private long id;
#OneToOne(mappedBy="order")
private Car car;
...
}
I have also Spring Data JPA repository with created custom query to find Order by Car:
public interface OrderRepository extends CrudRepository<Order, Long> {
Optional<Order> findByCar(Car car);
}
However, when I use the method findByCar(carWithNonNullOrder), I get the error:
2016-01-28 12:13:39,494 [main ] WARN SqlExceptionHelper - SQL Error: 0, SQLState: 07001
2016-01-28 12:13:39,494 [main ] ERROR SqlExceptionHelper - No value specified for parameter 1
2016-01-28 12:13:39,503 [main ] INFO TransactionContext - Rolled back transaction for test context [DefaultTestContext#61dde151 testClass = OrderServiceIT, testInstance = com.carsystem.server.OrderServiceIT#b25b095, testMethod = shouldMakeOrder#OrderServiceIT, testException = org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet, mergedContextConfiguration = [MergedContextConfiguration#507b79f7 testClass = OrderServiceIT, locations = '{classpath:context/app-context.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]].
2016-01-28 12:13:39,504 [main ] INFO GenericApplicationContext - Closing org.springframework.context.support.GenericApplicationContext#ff5b51f: startup date [Thu Jan 28 12:13:31 CET 2016]; root of context hierarchy
2016-01-28 12:13:39,506 [main ] INFO tainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
org.springframework.dao.InvalidDataAccessResourceUsageException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:242)
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:225)
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417)
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208)
at com.sun.proxy.$Proxy41.findByCar(Unknown Source)
at com.carsystem.server.OrderMapper.map(OrderMapper.java:25)
at com.carsystem.server.OrderServiceImpl.listOrders(OrderServiceImpl.java:90)
at com.carsystem.server.OrderServiceIT.shouldMakeOrder(OrderServiceIT.java:96)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
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.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
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.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:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: org.hibernate.exception.SQLGrammarException: could not extract ResultSet
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:106)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:95)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79)
at org.hibernate.loader.Loader.getResultSet(Loader.java:2116)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1899)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1875)
at org.hibernate.loader.Loader.doQuery(Loader.java:919)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:336)
at org.hibernate.loader.Loader.doList(Loader.java:2611)
at org.hibernate.loader.Loader.doList(Loader.java:2594)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2423)
at org.hibernate.loader.Loader.list(Loader.java:2418)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:501)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:371)
at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:216)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1326)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:87)
at org.hibernate.jpa.internal.QueryImpl.list(QueryImpl.java:606)
at org.hibernate.jpa.internal.QueryImpl.getResultList(QueryImpl.java:483)
at org.hibernate.jpa.criteria.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:50)
at org.springframework.data.jpa.repository.query.JpaQueryExecution$CollectionExecution.doExecute(JpaQueryExecution.java:114)
at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:78)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.doExecute(AbstractJpaQuery.java:100)
at org.springframework.data.jpa.repository.query.AbstractJpaQuery.execute(AbstractJpaQuery.java:91)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:462)
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:440)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:61)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136)
... 43 more
Caused by: java.sql.SQLException: No value specified for parameter 1
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:957)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:896)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:885)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:860)
at com.mysql.jdbc.PreparedStatement.checkAllParametersSet(PreparedStatement.java:2205)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2185)
at com.mysql.jdbc.PreparedStatement.fillSendPacket(PreparedStatement.java:2115)
at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:1936)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:70)
... 74 more
It seems that Spring Data JPA proxy can't find the Car entity. I have found quite similar question here: Spring Data query not working when query parameter is an entity, but in my case I'm fetching entities eagerly. Is it something wrong with mappings or Spring Data JPA?
EDIT
Hibernate query: select order0_.order_id as order_i1_3_, order0_.client_id as client_i4_3_, order0_.createdDate as createdD2_3_, order0_.returnDate as returnDa3_3_ from order order0_ left outer join car car1_ on order0_.order_id=car1_.order_id where car1_.car_id=?
I have noticed that the parameter Car which I used in custom query is also a class member of Order entity. However, when I call the query, I have a circular dependency between Car and Order: Order had a null Car.
Try this:
Order findOneByCar(Car car);
public interface OrderRepository extends JpaRepository<Order, Long> {
Order findByCar(Car car);
}
This should work.

Resources