ContextConfiguration annotation exception - java

I have a pretty simple Spring Boot project that was just upgraded from Spring Boot 1.2.5.RELEASE to Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE), and now my project won't compile.
Project:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableEncryptableProperties
public class MyApp extends WebMvcConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
Test that fails compilation (my only test ATM):
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = {MyApp.class})
#DirtiesContext
public class MyDAO_DataTest {
#Autowired
MyDAO dao;
#Test
public void whenDoingAtest() throws Exception {
//...
}
}
When I try to compile, it fails on my test file, saying:
org.springframework.core.annotation.AnnotationConfigurationException: In AnnotationAttributes for annotation [org.springframework.test.context.ContextConfiguration] declared on [class com.example.MyDAO_DataTest], attribute [locations] and its alias [value] are declared with values of [{}] and [{class com.example.MyApp}], but only one declaration is permitted.
I found the feature that's the origin of the exception, but I don't really understand what I can do about it.
Update I "fixed" the issue by changing this line:
#SpringApplicationConfiguration(classes = {MyApp.class})
... to this:
#ContextConfiguration(classes = {MyApp.class},
loader = SpringApplicationContextLoader.class)
effectively working around the issue and allowing myself to work, but I don't understand why I had to. #SpringApplicationConfiguration is described as Similar to the standard ContextConfiguration but uses Spring Boot's SpringApplicationContextLoader, so what's the deal?

Spring Boot 1.3.0.M5 (which then relies on Spring 4.2.0.RELEASE)
That is unfortunately incorrect: Spring Boot 1.3.0.M5 depends explicitly on Spring Framework 4.2.1, not 4.2.0.
The exception you are seeing was addressed in Spring Framework 4.2.1, specifically in the following issues.
https://jira.spring.io/browse/SPR-13325
https://jira.spring.io/browse/SPR-13345
And changes made to #SpringApplicationConfiguration in Spring Boot 1.3.0 M5 require Spring Framework 4.2.1. See the following issue for details.
https://github.com/spring-projects/spring-boot/issues/3635
Thus, ensuring that you are running against Spring Framework 4.2.1 should resolve your problem.
Regards,
Sam

Related

Spring Boot Integration test mock external dependency

I'm trying to create integration tests for my Spring Boot app. The idea is to launch an embedded postgres db and run http calls with TestRestTemplate to my controllers.
The problem is my project has a dependency we use for redis queues.
<dependency>
<groupId>com.github.sonus21</groupId>
<artifactId>rqueue-spring-boot-starter</artifactId>
<version>2.9.0-RELEASE</version>
</dependency>
I've tried to mock out the dependencies and most of them work, but with this one it complains I guess because it is a #Configuration not a #Component:
Dependency config class:
#Configuration
#AutoConfigureAfter({RedisAutoConfiguration.class})
#ComponentScan({"com.github.sonus21.rqueue.web", "com.github.sonus21.rqueue.dao"})
public class RqueueListenerAutoConfig extends RqueueListenerBaseConfig {
public RqueueListenerAutoConfig() {
}
...
}
My test config class
#TestConfiguration
public class TestRestTemplateConfig {
#Bean
#Primary
#Order(Ordered.HIGHEST_PRECEDENCE)
public RqueueListenerAutoConfig rqueueListenerAutoConfig() {
return Mockito.mock(RqueueListenerAutoConfig.class);
}
....
}
I've tried with #AutoConfigureOrder(1) at my config class but the original RqueueListenerAutoConfig launches before anything and my mocked beans haven't been declared yet.
To be honest mocking every service on that dependency is a pain, but I haven't figured out a way to mock the whole dependency with a single configuration. I tried not loading the dependency when I'm on the test profile but since it runs spring context my code needs it.
My test class has the following config:
#SpringBootTest
#Import(TestRestTemplateConfig.class)
#ActiveProfiles("test")
public class TestClass {
...
}
Any clues?
Thanks.
Try
#EnableAutoConfiguration(exclude=RqueueListenerAutoConfig.class)

Why is WebMvcConfigurer being loaded?

I'm new to Spring and testing a Spring Data project with Postgresql/JPA and MongoDB components. My Test class has the following annotations:
#SpringBootApplication
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringMongoConfig.class, PgRepository.class, MongodbRepository.class})
public class PerfTest {
#Autowired
private PgRepository pgRepo;
#Autowired
private MongodbRepository mongoRep;
For some reason the spring-context module is trying to load WebMvcConfigurer while resolving bean classes, giving me a NoClassDefFoundError.
Is the Spring Boot Autoconfigure trying to initiate a full web controller suite? If so, why? I'm really just interested in Spring Data. Should I avoid Spring Boot entirely?
You shouldn't annotate a test class as a #SpringBootApplication. This annotation is used to define a class in your main code base which contains a main() method to spin up your Spring boot container with auto-configuration.
If it's Spring data you are interested in testing then your tests will need to point to a #Configuration class which is annotated with #EnableJpaRepositories this will allow your repository interfaces to be autowired.
I don't know what is in your SpringMongoConfig class but if this contains that annotation then all you need to do is:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {SpringMongoConfig.class})
public class PerfTest {
If not then you need to set up this configuration and include it in the #ContextConfiguration of the test.
Another option which is a bit more heavyweight but will guarantee everything is available for your test (provided your Spring boot application is set up correctly) is to mark your test with #SpringBootTest this will automatically load the whole Spring boot context for the application. If it has trouble finding your main class you can point it in the right direction by providing the class in the annotation:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyMainClass.class)
public class PerfTest {
You need to add #Component to your repository interface. Spring loads the component class first and then #AutoWiring & Initialization of variables will happen.

Unable to use #DataJpaTest if Spring security is on classpath

I am trying to update my test cases to use the #DataJpaTest. However, I am encountering some issues that appear to be related to Spring Security. The following is an example of the test class.
#RunWith(SpringRunner.class)
#DataJpaTest
public class ExampleRepositoryTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
#Inject
private ExampleRepository repository;
#Test
public void test() throws Exception {
...
}
I keep getting the error java.lang.IllegalStateException: Failed to load ApplicationContext due to the missing bean org.springframework.security.config.annotation.ObjectPostProcessor.
The project is a RESTful application with Spring security. The original test case created a full Spring Boot context using #SpringBootTest. The #DataJpaTest is supposed to help me test the JPA slice, which is exactly what I want.
Any help would be greatly appreciated. What am I missing?
I got the same error.
for my case, I have added #SpringBootApplication and #EnableResourceServer on the same class.
when I move #EnableResourceServer to another configuration class, the error is gone.

Spring boot + Spring security with AspectJ not working

I am trying to configure spring global method security with AspectJ advice mode so I can use #PreAuthorize annotations in all #Configurable annotated classes. This my java configs:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, mode = AdviceMode.ASPECTJ)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
and:
#EnableCaching
#SpringBootApplication
#EnableSpringConfigured
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
public class WebApplication extends WebMvcConfigurerAdapter
This is my #Configurable class:
#Configurable
public class Entity {
#PreAuthorize("hasPermission(this, 'publish')")
public void method() { }
}
I also added spring-security-aspects as dependency. From AspectJ logs I can clearly see that Spring security related aspects are applied on my #Configurable classes however as soon as I create instance of these classes I get this exception:
Post-processor tried to replace bean instance of type [com.example.Entity] with (proxy) object of type [com.sun.proxy.$Proxy130] - not supported for aspect-configured classes!
I am using spring boot version 1.2.1 therefore spring security version is 3.2.5 . This seems to be bug that was discussed here : Spring Security AspectJMode with #EnableGlobalMethodSecurity not working
However this bug should not affect my version of spring security... Is there any workaround for this issue?
Ok I have solved this. It was problem with spring boot's SecurityAutoConfiguration class. I had to exclude it from auto configuration and configre spring security manually - not very big deal, but anyway...

How to get Roo integration tests to work with AnnotationConfigContextLoader

I have been running roo generated integration tests for quite a while with XML-based spring configuration and spring 3.1. However, I have recently changed from XML-based configuration to java based configuation and also upgraded from Spring 3.1 to Spring 4.0.
Unfortunately, my roo genenerated integration tests now fail with the exception:
java.lang.IllegalStateException: Test class [com.bulb.learn.domain.CounterIntegrationTest] has been configured with #ContextConfiguration's 'locations' (or 'value') attribute {classpath*:/META-INF/spring/applicationContext*.xml}, but AnnotationConfigContextLoader does not support resource locations.
at org.springframework.test.context.support.AnnotationConfigContextLoader.validateMergedContextConfiguration(AnnotationConfigContextLoader.java:164)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:111)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 32 more
I know this is being caused by this line in the roo generated aspect file:
declare #type: CounterIntegrationTest: #ContextConfiguration(locations = "classpath*:/META-INF/spring/applicationContext*.xml");
That is because I use this for my main test class base class:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles(profiles = "junit")
#ContextConfiguration(classes = { CoreConfig.class }, loader = AnnotationConfigContextLoader.class)
public abstract class CoreIntegrationTest {
...
}
Here is how I define the class that is annotated by #RooIntegrationTest
#RooIntegrationTest(entity = Counter.class, transactional = false)
public class CounterIntegrationTest extends CoreIntegrationTest {
However, I am not sure how to fix it.
The roo tests used to run fine. They also run fine with just upgrading to Spring 4.0. They also run fine with just changing to java configuration for Spring 3.1. However, they don't work with both (Spring 4.0 with Java config)
Does anyone have any ideas how I can get these to work without simply removing them from roo control and removing the offending line myself?
Thanks in advance!
Turns out that Roo looks at the annotated class to see if it already has a #ContextConfiguration before it adds one to the aspect. Unfortunately, it doesn't check to see if it has inherited a #ContextConfiguration.
I was able to solve the issue by adding a default #ContextConfiguration to the annotated class like this:
#ContextConfiguration
#RooIntegrationTest(entity = Counter.class, transactional = false)
public class CounterIntegrationTest extends CoreIntegrationTest {
This prevents Roo from generating its own, and therefore the error goes away.

Categories

Resources