Disable #EnableAutoConfiguration - java

I wonder how I can get rid of #EnableAutoConfiguration.
The spring boot documentation mentions that
If you need to find out what auto-configuration is currently being
applied, and why, starting your application with the --debug switch
but I can't find which auto-configurations are applied in the shell.
How does it look like and how do I import / enable just the necessary configurations for my application?
I'm especially interested to just load the spring data autoconfiguration for fast running integration tests.
== Update ==
Adding
#RunWith(SpringJUnit4ClassRunner.class)
#EntityScan("persistence.entities")
#EnableJpaRepositories("persistence.repositories")
#ActiveProfiles("dev")
#Configuration
#Import({ AopAutoConfiguration.class, AopAutoConfiguration.JdkDynamicAutoProxyConfiguration.class,
AuditAutoConfiguration.class, DataSourceAutoConfiguration.class,
DataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class,
DataSourcePoolMetadataProvidersConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
JpaBaseConfiguration.class, JpaRepositoriesAutoConfiguration.class,
JtaAutoConfiguration.class, ManagementServerPropertiesAutoConfiguration.class,
PersistenceExceptionTranslationAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
ServerPropertiesAutoConfiguration.class, SpringDataWebAutoConfiguration.class })
#EnableIntegration
#SpringApplicationConfiguration(classes = QueryTests.class)
public class QueryTests {...
to my JUnit test now throws an java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages (see below).
Caused by: java.lang.IllegalStateException: Unable to retrieve #EnableAutoConfiguration base packages
at org.springframework.boot.autoconfigure.AutoConfigurationPackages.get(AutoConfigurationPackages.java:77) ~[spring-boot-autoconfigure-1.2.5.RELEASE.jar:1.2.5.RELEASE]
at org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport.getBasePackages(AbstractRepositoryConfigurationSourceSupport.java:77) ~[spring-boot-autoconfigure-1.2.5.RELEASE.jar:1.2.5.RELEASE] ...

To see the Spring Boot stuff in the logs I add --debug to Program Arguments when I run that my Boot application from the IDEA.
From command line it looks like:
D:\Java\jdk8\bin\java -Didea.launcher.port=7533 "-Didea.launcher.bin.path=D:\IntelliJ IDEA\bin" -Dfile.encoding=windows-1252 -classpath "[SOME CP]" com.intellij.rt.execution.application.AppMain org.springframework.integration.samples.dsl.cafe.lambda.Application --debug
With that I can see in the console something like this:
=========================
AUTO-CONFIGURATION REPORT
=========================
Positive matches:
-----------------
AopAutoConfiguration
- #ConditionalOnClass classes found: org.springframework.context.annotation.EnableAspectJAutoProxy,org.aspectj.lang.annotation.Aspect,org.aspectj.lang.reflect.Advice (OnClassCondition)
- matched (OnPropertyCondition)
AopAutoConfiguration.JdkDynamicAutoProxyConfiguration
- matched (OnPropertyCondition)
GenericCacheConfiguration
- Automatic cache type (CacheCondition)
And so on.
For you second question there are two ways:
Disable undesired AutoConfiguration using #SpringBootApplication(exclude)
Don't rely on the Boot and just import required configurations. For example:
#Configuration
#Import({PropertyPlaceholderAutoConfiguration.class, ServerPropertiesAutoConfiguration.class,
EmbeddedServletContainerAutoConfiguration.class, DispatcherServletAutoConfiguration.class})
#EnableIntegration
public static class ContextConfiguration {

Related

How to resolve additional configuration file based on profile in Spring Boot?

I have a files structure like this:
- main/resources
- application.yml
- externalApi.yml
- application-dev.yml
- externalApi-dev.yml
- test/resources
- application-test.yml
- externalApi-test.yml
Now in ApiWebClient class I want to use this additional file "externalApi.yml" based on active profile. I used #PropertySource like this:
#PropertySource(value = "classpath:externalApi-${spring.profiles.active}.yml", factory = YamlPropertySourceFactory.class)
public class ApiWebClientImpl implements ApiWebClient {
and everything looks fine, application starts. The problem starts in the tests:
#SpringBootTest(classes = TestApplication.class)
#EnableConfigurationProperties
#ConfigurationPropertiesScan(basePackages = "com.xyz.testapplication")
#ActiveProfiles(value = "test")
public class ApiWebClientTest {
When I ran it with maven (with "test" profile or without it) like this: mvn clean install -Ptest I've got error message that says
java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.profiles.active' in value "classpath:externalApi-${spring.profiles.active}.yml
So I've added it manually (#ActiveProfiles somehow does not work):
#SpringBootTest(classes = AdapterTestApplication.class, properties = "spring.profiles.active=test")
and this is working properly but I don't want to update all of the spring boot tests with this part properties = "spring.profiles.active=test". What if I will have like 200 tests? How to do it automatically? Why it does not take proper config file when I run it? Maybe there is way to get rid off ${spring.profiles.active} in annotation?

How to check if an spring boot application has a certain annotation in autoconfiguration class

I am creating my own spring boot starter to centralise some common configurations in my projects. I would like to let on of my #Configuration classes be only matched, if my spring boot app is annotated in a certain way like so:
#SpringBootApplication
#EnableResourceServer
public class MyApplication {
...
When i use #ConditionalOnClass:
#Configuration
#ConditionalOnClass({EnableResourceServer.class})
class ResourceServerAutoConfiguration
the auto configuration matched when the dependency is used even when the app is not a resource server (annotation is not present).
Is there a condition that only matches when the spring boot app has a certain annotation present?
I believe the simplest way would be to
Add the #Import annotation to your #EnableResourceServer annotation class and pass in your configuration class
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Import(ResourceServerAutoConfiguration.class)
public #interface EnableResourceServer {
}
Remove ResourceServerAutoConfiguration from the auto configuration block of the spring.factories file so it is no longer autoconfigured.
This should result in the config only being loaded when the annotation is present ie.
#SpringBootApplication
#EnableResourceServer
public class NotificationAdapterApplication {
}

SpringExtension without an explicit configuration?

I have a JUnit5 test with SpringExtension. All I need is environment variables to be injected via Spring's #Value:
#ExtendWith(SpringExtension.class)
class MyTest {
#Value("${myValue}") String myValue;
...
Doing so, I get an error saying:
Failed to load ApplicationContext Caused by:
java.lang.IllegalStateException: Neither GenericGroovyXmlContextLoader nor AnnotationConfigContextLoader was able to load an ApplicationContext
Of course, Spring needs to have a context configuration, so I put it into the test code:
#ExtendWith(SpringExtension.class)
#ContextConfiguration
class MyTest {
#Value("${myValue}") String myValue;
#Configuration
static class TestConfig { /*empty*/ }
...
While this works, it looks like a lot of unnecessary boilerplate code to me. Is there a simpler way?
UPDATE
One shorter variant would be to use #SpringJUnitConfig which brings both #ContextConfiguration and #ExtendWith(SpringExtension.class) out of the box.
But a configuration class (even an empty one) is still needed.
As has been pointed out in other answers and comments, you need to specify an empty configuration source, specifically a #Configuration class, XML config file, Groovy config file, or ApplicationContextInitializer.
The easiest way to do that is to create your own composed annotation that predefines the empty configuration.
If you introduce the following #EmptySpringJUnitConfig annotation in your project, you can use it (instead of #SpringJUnitConfig) wherever you want an empty Spring ApplicationContext.
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.TYPE)
#Documented
#Inherited
#SpringJUnitConfig(EmptySpringJUnitConfig.Config.class)
public #interface EmptySpringJUnitConfig {
#Configuration
class Config {
}
}
You cannot run a Spring based test without a configuration. The Spring Test Context Framework (TCF) expects/requires an ApplicationContext. To create an ApplicationContext a form configuration (xml, Java) needs to be present.
You have 2 options to make it work
Use an empty configuration, emtpy XML file or empty #Configuration class
Write a custom ContextLoader which creates an empty application context.
Option 1 is probably the easiest to achieve. You could create a global empty configuration and refer that from the #ContextConfiguration.
In SpringBoot to run a spring application context, you need to use the #SpringBootTest annotation on the test class:
#ExtendWith(SpringExtension.class)
#SpringBootTest
class MyTest {
#Value("${myValue}") String myValue;
...
UPDATED:
Or if you use just a Spring Framework (without spring boot) then test configuration depends on a version of the spring framework which you use, and on the spring configuration of your project.
You can set configuration files by the using of #ContextConfiguration, if you use java config then it will be something like that:
#ContextConfiguration(classes = AppConfig.class)
#ExtendWith(SpringExtension.class)
class MyTest {
...
or if you use xml configuration:
#ContextConfiguration("/test-config.xml")
#ExtendWith(SpringExtension.class)
class MyTest {
...
both of these depends on your project configuration structure and list of beans which you need in tests.
More details about context configuration: https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html#spring-testing-annotation-contextconfiguration
If you use the Spring Framework older then 5.0 then you can find useful this library: https://github.com/sbrannen/spring-test-junit5

How to finally and completely disable hibernate in Spring Boot

In a Spring Boot project that is not using JPA/Hibernate (but which cannot help but have these libraries on the classpath; long story, but completely unchangeable in this context), I need to stop whatever autoconfiguration is causing the error:
java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
I am aware that I have to explicitly exclude JPA/Hibernate autoconfiguration. I do so in both the #SpringBootApplication-annotated Java class and also in the application.properties file.
#SpringBootApplication
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
#ComponentScan(basePackages = { "com" })
#EnableAsync
public class Application extends SpringBootServletInitializer {
...
}
and
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Additionally, I've verified that these autoconfigurations are being excluded, by looking in the --debug output:
Exclusions:
-----------
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
Still, it fails when I don't have a JPA #Entity defined.
Why would this be?

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