Mockito.verify() in Groovy causing ambiguous method error for a Spring #MockBean - spring

I am trying to verify that a method was called on a Spring #MockBean:
Mockito.verify(rabbit).convertAndSend(
Mockito.isA(String.class),
Mockito.isA(String.class),
Mockito.isA(Object.class)
)
I am doing this in a Spock test, and getting the following error:
Caused by: groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method org.springframework.amqp.rabbit.core.RabbitTemplate$MockitoMock$2020468097#convertAndSend.
Cannot resolve which method to invoke for [null, null, null] due to overlapping prototypes between:
[class java.lang.String, class java.lang.Object, interface org.springframework.amqp.core.MessagePostProcessor]
[class java.lang.Object, interface org.springframework.amqp.core.MessagePostProcessor, class org.springframework.amqp.rabbit.connection.CorrelationData]
... 1 more
Is there a better way to use Mockito syntax to point it to the particular method?

Related

#WebMvcTest with #Import does not work. Test context always asks for #Repository beans

Using Spring Boot 2.7.3 I can not create a simple integration test for my API using #WebMvcTest.
Here is my setup:
// GameServerApplicationTests.kt
#SpringBootTest
class GameServerApplicationTests {
#Test
fun contextLoads() { }
}
// CraftService.kt
#Service
class CraftService {
fun getAll(): List<String> {
return listOf("foo", "bar")
}
}
// CraftApiTest.kt
#WebMvcTest
#Import(value = [CraftService::class])
class CraftApiTest {
#Autowired
private lateinit var testRestTemplate: TestRestTemplate
#Test
fun `should do accept craft all endpoint`() {
val response = testRestTemplate.getForEntity("/craft/all", String::class.java)
assertThat(response.statusCode).isEqualTo(HttpStatus.OK)
}
}
When I run the test I see this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'itemRepository' defined in com.gameserver.item.ItemRepository defined in #EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#3fba233d' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#3fba233d': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
I have no idea why it is looking for the itemRepository bean at all. I never asked for that.
I then added this
#WebMvcTest
#ComponentScan(excludeFilters = [ComponentScan.Filter(Repository::class)]) // <<
#Import(value = [CraftService::class])
Which resulted in this exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'playerRepository' defined in com.gameserver.player.PlayerRepository defined in #EnableJpaRepositories declared on GameServerApplication: Cannot create inner bean '(inner bean)#30c1da48' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#30c1da48': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
Which confuses me even more. I explictly excluded all #Repository beans - but it just skipped ItemRepository and then asked for PlayerRepository now.
I am totally lost and have no idea why I am not able to setup a simple integration test for my API endpoint.
EDIT #1:
Other tests run just fine:
EDIT #2:
I tried to use a #Configuration bean for #Import.
// CraftApiTestConfiguration
#Configuration
class CraftApiTestConfiguration {
#Bean
fun getCraftService(): CraftService {
return CraftService()
}
}
// CraftApiTest.kt
#WebMvcTest
#Import(CraftApiTestConfiguration::class)
class CraftApiTest { // ... }
That did not help either. It just gave me the second exception mentioned above (the one asking for playerRepository)
I'll try to answer although without seeing the actual code it might not be correct.
So #WebMvcTest loads a "slice" of your application with all the beans annotated with #RestControllers. It doesn't load #Service or #Repository annotated beans.
When you run the test with #WebMvcTest annotation it will load all the controllers, and if, by accident the controller references others than the reference on the service (here I can't say for sure what it is), you might end up loading the stuff that you don't actually need.
Now when you use #WebMvcTest there are two things you can/should do:
Work with MockMvc instead of rest template that queries a web server, its not a full-fledged web layer test anyway.
Try using #WebMvcTest with your controller only:
#WebMvcTest(CraftApisController.class)
Also instead of injecting the real implementation of service, you can use #MockBean so that the real service implementation will be covered by a regular unit test (without spring at all, just plain JUnit/Mockito) and this test could check that your annotations are defined correctly

Creating A pointcut using args designator with no types results in BeanCurrentlyInCreationException

Using Spring AOP, when attempting to create a Pointcut using the designator args while not providing any types results in a series of exceptions starting with BeanCurrentlyInCreationException
The Example
object _001_Spring_AOP_Pointcut_Args_NoArgs {
open class BeanA {
open fun m() {
println("BeanA#m()")
}
}
#Aspect
class AspectA {
#Pointcut("args()")
private fun pc_noArgs() = Unit
#After("sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs.AspectA.pc_noArgs()")
private fun ac_noArgs() = println("ac_noArgs")
}
#Configuration
#EnableAspectJAutoProxy(proxyTargetClass = true)
open class Config {
#Bean
open fun beanA(): BeanA = BeanA()
#Bean
open fun aspectA(): AspectA = AspectA()
}
fun runJava() {
AnnotationConfigApplicationContext(Config::class.java)
}
}
The Run Method
#Test
fun test_run() {
_001_Spring_AOP_Pointcut_Args_NoArgs.runJava()
}
The Exception Summary
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'beanA' defined in sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$Config: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$BeanA]: Factory method 'beanA' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'aspectA' defined in sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$Config: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs$AspectA]: Factory method 'aspectA' threw exception; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'aspectA': Requested bean is currently in creation: Is there an unresolvable circular reference?
args() vs. execution(* *())
This is an unusual way of intercepting all methods without parameters. I would rather make it more explicit and use execution(* *()) instead. If you ever migrate from Spring AOP to AspectJ, you will notice that args() matches all kinds of pointcuts there, e.g. call, initialization, preinitialization, staticinitialization, get and constructor calls/executions without parameters.
Pointcut scoping
Here in Spring AOP your problem might be another one, though: Your pointcut is too broad. It matches many joinpoints in Spring beans, also in Spring or third-party classes themselves. So you want to limit the scope of your pointcut, e.g. something like
execution(* *()) && within(my.own.package.**)
When to (not) use fully qualified class names in pointcuts
BTW, if your pointcut is defined in the very same class as the advice using it, it should not be necessary to use a fully qualified class name, i.e. instead of
#After("sero4.spring.z_added._001_Spring_AOP_Pointcut_Args_NoArgs.AspectA.pc_noArgs()")
you could use
#After("pc_noArgs()")
Inline pointcuts
If you have no plans to re-use the same pointcut in other advices, just get rid of #Pointcut and define an inline pointcut such as
#After("execution(* *()) && within(my.own.package.**)")
Advices should be public
While it is OK to define the #Pointcut method as private if you do not refer to it from other classes, the #After advice should be public. It might work in Spring AOP, but is against conventions. Again, if you ever migrate to AspectJ, you will even get a compile error because an AspectJ advice must be public.
The code shared fails with the following exception -
org.springframework.beans.factory.BeanCurrentlyInCreationException
, when the pointcut expression has a scope within the package the aspect class resides.
Example:
Fully qualified names for the beans :
rg.spring.boot.AspectA
rg.spring.boot.bean.BeanA
And a pointcut expression like the following would fail:
#Pointcut("args() && within(rg.spring.boot..*)")
whereas, the following pointcut expression succeeds :
#Pointcut("args() && within(rg.spring.boot.bean..*)")
The exception, as per me, is because the pointcut targets framework methods of the aspect during initialization. To resolve the exception, you may move the bean to a specific package and fine tune the scope of the pointcut expression for that package.

Spring Batch - "job" scoped beans can not be injected into "job" or "step" scoped beans

I am using spring batch version 3.0.2.RELEASE and spring framework version 3.2.12.RELEASE. And I am trying to inject a job scoped bean to another job scoped bean.
My configuration looks like this
<bean id="beanA" class="com.trial.BeanA" scope="job" >
<property name="beanB" ref="beanB" />
</bean>
<bean id="beanB" class="com.trial.BeanB" scope="job"/>
It throws an exception with details:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.beanA' defined in class path resource [trial-context.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.sun.proxy.$Proxy1 implementing com.trial.BeanB,org.springframework.beans.factory.InitializingBean,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'com.trial.BeanB' for property 'beanB'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy1 implementing com.trial.BeanB,org.springframework.beans.factory.InitializingBean,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.trial.BeanB] for property 'beanB': no matching editors or conversion strategy found
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:331)
at org.springframework.batch.core.scope.JobScope.get(JobScope.java:103)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:327)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:34)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:184)
at com.sun.proxy.$Proxy13.getValue(Unknown Source)
at org.springframework.batch.core.listener.CompositeJobExecutionListener.beforeJob(CompositeJobExecutionListener.java:73)
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:301)
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:49)
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'com.sun.proxy.$Proxy1 implementing com.trial.BeanB,org.springframework.beans.factory.InitializingBean,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised' to required type 'com.trial.BeanB' for property 'beanB'; nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy1 implementing com.trial.BeanB,org.springframework.beans.factory.InitializingBean,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.trial.BeanB] for property 'beanB': no matching editors or conversion strategy found
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:464)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:495)
at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:489)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1465)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1424)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1160)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
... 18 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type [com.sun.proxy.$Proxy1 implementing com.trial.BeanB,org.springframework.beans.factory.InitializingBean,org.springframework.aop.scope.ScopedObject,java.io.Serializable,org.springframework.aop.framework.AopInfrastructureBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised] to required type [com.trial.BeanB] for property 'beanB': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:267)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:449)
... 24 more
Even I try to inject a "job" scoped bean to a "step" scoped bean, it fails and throws a similar exception.
How can I solve the issue?
You are using java proxying which requires interfaces, yet your BeanB doesn't implement an interface that BeanA is coded against. You need to either switch to dynamic subclassing or have BeanB implement an interface and have BeanA expect that interface.

Dependency Injection in JSR-303 ConstraintValidator

I have the same problem that the guy from this thread has.
More precisely I get the following error, when trying to inject a bean in my custom validator that implements CustomValidator interface (it's a NPE when accessing the bean i wanted to inject):
javax.validation.ValidationException: HV000028: Unexpected exception during isValid call.
at org.hibernate.validator.internal.engine.ConstraintTree.validateSingleConstraint(ConstraintTree.java:294)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:164)
at org.hibernate.validator.internal.engine.ConstraintTree.validateConstraints(ConstraintTree.java:125)
at org.hibernate.validator.internal.metadata.core.MetaConstraint.validateConstraint(MetaConstraint.java:86)
...
Caused by: java.lang.NullPointerException
Do you have a solution for this? Maybe an example? Because I tried the solutions offered on the other thread and nothing worked.
Any help is appreciated. Thanks.
You should not create validator factory on your own (Validation.buildDefaultValidatorFactory()) if you want to use Spring based constraint validators.
You should let Spring autowire correct factory to your bean:
#Controller
public class MyController {
#Autowired
private ValidatorFactory validatorFactory;
// ... handler methods
}

spring aop - exception while creating advice around JdbcTemplate methods

I've a web application that uses apache dbcp and spring jdbc to perform database operations on an oracle database. I need to write a performance logger that logs the individual times of each database operation. I tried writing an around advice on all 'execute' methods of org.springframework.jdbc.core.JdbcTemplate but it results in an error when spring gets initialized. The logger class and the exception stacktrace is as follows:-
I also tried to use CGLIB proxies by enabling but it errors out on dao classes that extends from spring's StoredProcedure class and use constructor injection.
#Aspect
public class Logger {
#Around("this(org.springframework.jdbc.core.JdbcTemplate) && execution(* execute(*))")
public Object invoke(ProceedingJoinPoint pjp) throws Throwable {
long time = System.currentTimeMillis();
Object result = pjp.proceed();
LOGGER.debug("time consumed = " + (System.currentTimeMillis() - time));
return result;
}
Exception stacktrace:
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'myDao' defined in class path resource [spring/my-dao.xml]: Unsatisfied dependency expressed through constructor argument with index 0 of type [org.springframework.jdbc.core.JdbcTemplate]:
Could not convert constructor argument value of type [$Proxy7] to required type [org.springframework.jdbc.core.JdbcTemplate]:
Failed to convert value of type '$Proxy7 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised'
to required type 'org.springframework.jdbc.core.JdbcTemplate';
nested exception is
java.lang.IllegalStateException: Cannot convert value of type [$Proxy7 implementing org.springframework.jdbc.core.JdbcOperations,org.springframework.beans.factory.InitializingBean,org.springframework.aop.SpringProxy,org.springframework.aop.framework.Advised]
to required type [org.springframework.jdbc.core.JdbcTemplate]:
no matching editors or conversion strategy found
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:702)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196)

Resources