Spring-Boot: #EnableRedisHttpSession annotation ignores profiles (when negating them) - spring

I´m running into this weird issue with Spring Boot Profiles and #EnableRedisHttpSession:
If I use this setup, everything is correct:
#Configuration
#Profile({"prod"})
#EnableRedisHttpSession
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
Neither WebSecurity nor RedisSession are initialized when running in other profiles than prod.
On the other hand, if I use "negated" profiles, both the security and redis logic are initialized:
#Configuration
#Profile({"!dev", "!test"})
#EnableRedisHttpSession
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
I´m am doing this, since I want to run using custom profiles given from the outside.
I have tried several workarounds:
For Security, I have disabled it by using this property: security.ignored: /**
However, I am unable to disable the Redis Session. I have tried this:
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
And this too: spring.data.redis.repositories.enabled=false but without success.
I am running Spring-Boot v1.5.16.RELEASE
Edit: This is the stacktrace shown when initializing Redis (which is not wanted in this profile):
Caused by: org.springframework.data.redis.RedisConnectionFailureException: Cannot get Jedis connection; nested exception is redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:204) ~[spring-data-redis-1.8.13.RELEASE.jar:na]
at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:348) ~[spring-data-redis-1.8.13.RELEASE.jar:na]
at org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration$EnableRedisKeyspaceNotificationsInitializer.afterPropertiesSet(RedisHttpSessionConfiguration.java:249) ~[spring-session-1.3.3.RELEASE.jar:na]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1692) ~[spring-beans-4.3.18.RELEASE.jar:4.3.18.RELEASE]
at org.springframework.beans.fa

I haven't done Spring in forever, but I did find this answer which suggests that you cannot "negate" profiles: Can I negate (!) a collection of spring profiles?

Related

Data JPA Test with reactive spring

I want to test the repository layer and I'm using spring webflux. My test class is as follows
#RunWith(SpringRunner.class)
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}
Even though this would work in spring-mvc when using spring-weblux I get the following error.
Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
...
Caused by: org.springframework.context.ApplicationContextException: Unable to start ReactiveWebApplicationContext due to missing ReactiveWebServerFactory bean.
How to resolve this? If I am to start the whole application context with #SpringBootApplication it works. Any other options without using that?
The reason for this was that in the application.properties the application type was set as reactive.
spring.main.web-application-type=reactive
This tries to auto configure a web server in this case a reactive web server. As #DataJpaTest does not provide a bean for that, this fails. This can be fixed in either two ways.
One is by Adding an application.properties file in the resources directory of the test package and setting the value as,sprig.main-web-application-type=none solves this issue.
Or we can simple pass a property value to the annotation as follows. #DataJpaTest(properties = "spring.main.web-application-type=none")
If you are using Spring Boot 2+ then only #DataJpaTest is enough on test class.
So your test class should be
#DataJpaTest
public class DataTester {
#Autowired
private MyRepository repository;
#Test
.....
}

Spring Consul - disable for unit tests

Updated
My class listed below (ServiceDiscoveryConfiguration) is never being utilized. Even if I remove the #EnableDiscoveryClient to attempt to completely avoid the setup, it still attempts to connect to Consul.
The only thing that worked for me was removing the Consul Maven depdency completely:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
What can I do to prevent Consul for running for unit tests if not through the profile and annotation setup?
Original
I have an application using Spring Consul.
I have a class set up to enable discovery like this:
#Profile ("!" + Profiles.UNIT_TEST)
#Configuration
#EnableDiscoveryClient
public class ServiceDiscoveryConfiguration {
}
This should be disabling the Consul portion, if I am not mistaken. The base test class (it's an abstract shared between all of my unit tests) is setup up with the following annotations. This is where I think the problem is.
#SpringBootTest (classes = Service.class)
#WebAppConfiguration
#TestExecutionListeners (...)
#DirtiesContext
#ActiveProfiles (Profiles.UNIT_TEST)
#Test (...)
public abstract class AbstractBootTest extends AbstractTestNGSpringContextTests {
// ...
}
When I execute my tests I get:
Caused by: com.ecwid.consul.transport.TransportException:
java.net.ConnectException: Connection refused
This leads me to believe that the profile activation is not working or my syntax using the ! operator on the #Profile specification is not doing what I thought it was supposed to be doing. The root execution class itself has basic annotations including a #ComponentScan annotation that I know has the appropriate packages being scanned.
Assistance?
You can disable via
#TestPropertySource(properties = {"spring.cloud.consul.config.enabled=false"})
if you have bootstrap.properties file in your project, you should create bootstrap.properties file under test/resources:
spring.application.name=<service-name>
spring.cloud.bus.enabled=false
spring.cloud.discovery.enabled=false
spring.cloud.consul.enabled=false
spring.cloud.consul.config.enabled=false
This will disable consul integration in tests
Add below property in your application.properties file under test/resources
spring.cloud.discovery.enabled=false
spring.cloud.consul.enabled=false
spring.cloud.consul.config.enabled=false
This will disable consul integration while testing your application
The problem is that if you have spring-consul in the classpath it will try to auto-configure it anyway
The profile annotation is correct
#Profile ("!" + Profiles.UNIT_TEST)
the profile activation looks ok, also
#ActiveProfiles (Profiles.UNIT_TEST)
You wrote you are using ComponentScan, that is important, because #Profile annotation on a bean is ignored, if the bean is instantiated by a #Bean annotated method. May be you check again, to see, this does not happen ?
To narrow down the problem you can try :
set a breakpoint in the constructor of ServiceDiscoveryConfiguration, to see if it is instantiated or not
remove #EnableDiscoveryClient to see if this is really the cause of your problems

Spring Security - conditional WebApplicationInitializer

The documentation for Spring Security states that in order to use the Java Config we can extend the AbstractSecurityWebApplicationInitializer class which will set up all nesesarry beans for Spring Security to work. This approach is working fine, the initializer is run automatically and Spring Security is initialized correctly during application startup.
But right now i am facing a scenario when this initialization should be depended on a system property. So i would like to include my initializer class only when some system property is set (for example: app.enablesecurity=true) and NOT execute this initializer in any other case.
I failed to come up with any solution for that scenario because:
In AbstractSecurityWebApplicationInitializer the onStartup method is
marked final so i cannot override it and add a condition
If i just extend AbstractSecurityWebApplicationInitializer it is
always automatically picked up by Spring and instantiated (or at least Spring tries to create instance of it, it may fail), even if i
declare it as a private/inner/nested class.
So as far as i know the only possibility of conditionally including this initializer is to use cglib/javassist in order to dynamically create a class that extends AbstractSecurityWebApplicationInitializer.
Is there any other way? Maybe there is some method that will allow me to hide my implementation from being picked up by Spring and run it by hand at a later time?
You can use Config Class like this to configure your security behavior
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${app.enablesecurity}")
private boolean securityEnabled;
#Override
protected void configure(HttpSecurity http) throws Exception {
if (securityEnabled) {
http.csrf().disable();
...
} else {
http. ...
}
}
}

#Profile cause Unable to start EmbeddedWebApplicationContext

im trying to use #Profile functionality to separate production/dev environment configuration and 'tests' config. But when I add #Profile to my configuration class I get:
Exception in thread "main" org.springframework.context.ApplicationContextException: Unable to start embedded container; nested exception is org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:124)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:109)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:691)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:952)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:941)
at mypackage.configuration.PhoenixConfiguration.main(PhoenixConfiguration.java:26)
Caused by: org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.getEmbeddedServletContainerFactory(EmbeddedWebApplicationContext.java:174)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:147)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:121)
... 7 more
Configuration class looks like this:
#Configuration
#EnableAutoConfiguration
#ComponentScan("mypackage")
#EnableJpaRepositories(basePackages = "mypackage.repository")
#EntityScan(basePackages = "mypackage.phoenix.domain")
#PropertySource("classpath:properties/application-production.properties")
#EnableWebMvc
#Profile("production")
public class PhoenixConfiguration extends WebMvcConfigurerAdapter{
public static void main(String[] args) throws Exception {
SpringApplication.run(PhoenixConfiguration.class, args);
}
}
ive tried to set active profile to production in application-production.properties
spring.profiles.active=production (with and without " )
or cmd command: mvn spring-boot:run -Dspring.profiles.active=production
nothing helps. Ofcourse everything works when I remove #Profile, but then I my tests are using production database ; )
If you add the profile your whole application basically stops working because your main entry point is annotated with #Profile.
I suggest you let Spring Boot do its work at the moment it appears as if you are trying to work very hard around Spring Boot and you are making things, imho, too complex.
Spring Boot will autodetect Spring Data JPA and the fact that you have Spring Web on your classpath. So remove #EnableJpaRepositories and #EnableWebMvc and don't let your class extends WebMvcConfigurerAdapter.
Spring boot by default will load the application.properties for you instead of putting in in properties either place it in the root of your classpath or config. At least remove the #PropertySource as Spring Boot will just load it. If you want to keep the properties path add the spring.config.location property which then points to your properties directory.
Finally I would probably also rename the file to PhoenixApplication but that is just me. That should leave you with something like
#Configuration
#EnableAutoConfiguration
#ComponentScan("mypackage")
#EntityScan(basePackages = "mypackage.phoenix.domain")
public class PhoenixApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(PhoenixApplication.class, args);
}
}
Now simply put your production configuration in the application.properties and put another one in src/test/resources to contain your test configuration. At runtime only the first will be available when testing the latter will override properties from the first.
If you really want to use profiles I would suggest doing it the other way around, configure for production and override for test. Then simply add #ActiveProfiles to your test case.
#ActiveProfiles("test")
#SpringApplicationConfiguration(classes=PhoenixApplication.class)
public class YourTest {}
This will start a test which will load the default application.properties and a application-test.properties which you can simply place in src/test/resources.

Spring WebSecurityConfigurerAdapter keeps throwing IllegalStateException because of #Order

I have extended WebSecurityConfigurerAdapter, but every time I start Jetty, I get the exception:
java.lang.IllegalStateException: #Order on WebSecurityConfigurers must be unique. Order of 2147433647 was already used, so it cannot be used on com.xtl.mis.support.config.SecurityConfig$$EnhancerByCGLIB$$11a4eacf#332c45ff too.
I previously had not annotated the class with #Order and started getting the exception. Currently, I have my class annotated with #Order(Ordered.LOWEST_PRECEDENCE - 50000). I've tried several different values for this annotation, but always get the above exception saying the #Order must be unique and the one calculated was already used. I'm using Spring Security 3.1.4.RELEASE and Spring Security JavaConfig 1.0.0.M1.
I believe I've fixed this. I had a central #Configuration class called AppConfig which also had an #Import({SecurityConfig.class}) annotation on it. I removed the #Import annotation and added #ComponentScan and now it works.
When extending WebSecurityConfigurerAdapter in an integration test, you may as well replace..
#Import({SecurityConfig.class})
..by..
#ContextConfiguration(classes = SecurityConfig.class)

Resources