I'm trying to configure a second template resolver to be used by Thymeleaf. I also want the default resolver which looks under the templates folder but whatever I try I only end up with a single resolver.
In my project there is already a yaml configuration file which contains:
thymeleaf:
mode: LEGACYHTML5
cache: false
As a first step I've tried to add a configuration bean:
#Configuration
#EnableWebMvc
public class ThymeleafConfiguration extends WebMvcConfigurerAdapter implements ApplicationContextAware
{
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setTemplateResolver(templateResolver());
return engine;
}
private ITemplateResolver templateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/public/");
resolver.setTemplateMode("HTML");
return resolver;
}
}
But I never see a second resolver in org.thymeleaf.TemplateRepository, just the default.
I've further tried omdifying the YAML file with the following:
thymeleaf:
-
mode: LEGACYHTML5
cache: false
prefix: classpath:/public/
-
mode: LEGACYHTML5
cache: false
prefix: classpath:/templates/
But again I only get a single resolver created.
Anyone know how to do this or can see what I am doing wrong?
If you want to add multiple resolvers, you could use engine.addTemplateResolver instead of engine.setTemplateResolver() or use setTemplateResolvers() which takes in a Set.
#Configuration
#EnableWebMvc
public class ThymeleafConfiguration extends WebMvcConfigurerAdapter implements ApplicationContextAware
{
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException
{
this.applicationContext = applicationContext;
}
#Bean
public TemplateEngine templateEngine() {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.addTemplateResolver(templateResolverPublic());
engine.addTemplateResolver(templateResolverTemplates());
return engine;
}
private ITemplateResolver templateResolverPublic() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/public/");
resolver.setTemplateMode("HTML");
return resolver;
}
private ITemplateResolver templateResolverTemplates() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/templates/");
resolver.setTemplateMode("HTML");
return resolver;
}
}
P.S. On an other note if you want to use auto-configuration capabilities of Spring boot, you should avoid setting up your configuration manually (as you did in your configuration class) and instead just define properties in YAML which Spring Boot will use and will configure your template engine/resolvers. If you manually specify your configuration spring boot will not additionally configure the Thymeleaf engine/resolvers so the YAML properties w.r.t the configurations you defined will not be used i.e. you are basically overriding spring boots configurations.
Related
Trying to use SpringBoot with SpringData with Elasticache:
application.properties:
spring.redis.host=XXXX-dev.XXXX.clusXXXcfg.XXX.cache.amazonaws.com
spring.redis.port=6379
CacheConfiguration:
#Configuration
#PropertySource("classpath:application.properties")
public class CacheConfiguration {
#Value("${spring.redis.host}")
private String redisHostName;
#Bean
public RedisTemplate<String, Company> redisTemplate() {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
#Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory factory = new JedisConnectionFactory();
factory.setHostName(redisHostName);
factory.setUsePool(true);
return factory;
}
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Service call:
#Autowired
RedisTemplate<String, Company> redisTemplate;
private ValueOperations valueOperations;
#PostConstruct
private void init() {
valueOperations = redisTemplate.opsForValue();
}
#Override
public String createOtp(Company company) {
String token = UUID.randomUUID().toString();
valueOperations.set(token, company);
valueOperations.getOperations().expire(token, 5, TimeUnit.MINUTES);
return token;
}
Error:
org.springframework.data.redis.ClusterRedirectException: Redirect: slot 7228 to 10...:6379.*
redis.clients.jedis.exceptions.JedisMovedDataException: MOVED 7228 10...:6379.*
The question is - what is wrong with configuration?
You're running your Elasticache in Redis Cluster mode (only Redis Cluster responds with MOVED) but the connection factory is configured in standalone mode.
Spring Boot can auto-configure all the things you've set up manually for you. Basically, remove your CacheConfiguration class (or at least remove the majority of code):
#Configuration
public class CacheConfiguration {
#Bean
public RedisTemplate<String, Company> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Company> template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);
return template;
}
}
And then configure the following properties in your application.properties file:
spring.redis.cluster.nodes=<node_host>:<port> # Comma-separated list of "host:port" pairs to bootstrap from.
Spring Boot loads application.properties by default and the Redis auto-config configures a RedisTemplate<Object, Object> bean by default. Specializing beans is a valid use-case – do not duplicate what's already provided by the auto-config, especially if you want to achieve what auto-config does.
See also:
Common application properties
Externalized Configuration
I have a Spring Boot app using Thymeleaf 3 as the template engine for the app pages. We use the default configuration provided by spring-boot-starter-thymeleaf, with the HTML Thymeleaf templates under the src/main/resources/templates folder.
Now we would like to use Thymeleaf to generate also some javascript files, using the new javascript template mode. Those javascript templates could be located into the same HTML templates folder or another one (ex: src/main/resources/jstemplates).
I don't know if there is a way to add this configuration without changing anything in the default configuration provided by the spring-boot-starter-thymeleaf, or I have to create a full configuration for everything.
I've tried the first option with the following configuration, which works for the javascript templates, but then html templates don't work anymore.
The configuration:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
implements ApplicationContextAware {
private static final String UTF8 = "UTF-8";
#Autowired
private SpringTemplateEngine templateEngine;
#Autowired
private ThymeleafProperties properties;
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public ThymeleafViewResolver javascriptThymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(UTF8);
resolver.setContentType("application/javascript");
resolver.setViewNames(new String[] {".js"});
resolver.setCache(this.properties.isCache());
return resolver;
}
#Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/jstemplates/");
resolver.setSuffix(".js");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
return resolver;
}
}
A test javascript controller:
#Controller
public class JavascriptController {
#RequestMapping(method = RequestMethod.GET, value = "/test.js")
public String testjs() {
return "test";
}
}
The controller for the root page:
#Controller
public class MainController {
#RequestMapping(method = RequestMethod.GET, value = "/")
public String index(Model model) {
return "index";
}
}
There is a test.js file in the src/main/resources/jstemplates folder. If I try the url http://localhost:8080/test.js, it works as expected. But if I try, for example, the main url (http://localhost:8080/) it fails with the following error:
Caused by: java.io.FileNotFoundException: class path resource
[jstemplates/index.js] cannot be opened because it does not exist
It should be looking for the templates/index.html instead, so it seems the javascriptTemplateResolver overrides or takes precedence over de default one, without falling back to it.
Is there a way to add another template mode support integrated with the default Thymeleaf configuration, or I need to configure everything from scratch?
After some debugging I finally found the solution. It seems the SpringResourceTemplateResolver doesn't check by default if the template really exists. In my example configuration, the first template resolver is the one configured for the javascript templates, and it was creating a View without looking first if the template exists.
To solve it the template checkExistence property must be set to true. Ex:
#Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("classpath:/jstemplates/");
resolver.setSuffix(".js");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
resolver.setCheckExistence(true);
return resolver;
}
The only problem I see with this configuration is that if we create a js view with the same name as a html view, it will always get the javascript one.
Edit
To solve that last issue I've made some changes in the configuration:
Remove the .js suffix in the resolver configuration
When a controller gives a javascript view name, that name already includes the .js suffix.
The final configuration is as follows:
#Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter
implements ApplicationContextAware {
private static final String UTF8 = "UTF-8";
#Autowired
private ThymeleafProperties properties;
#Autowired
private TemplateEngine templateEngine;
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
#Bean
public ThymeleafViewResolver javascriptThymeleafViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(this.templateEngine);
resolver.setCharacterEncoding(UTF8);
resolver.setContentType("application/javascript");
resolver.setViewNames(new String[] {"*.js"});
resolver.setCache(this.properties.isCache());
return resolver;
}
#Bean
public SpringResourceTemplateResolver javascriptTemplateResolver() {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(this.applicationContext);
resolver.setPrefix("classpath:/templates/js/");
resolver.setTemplateMode(TemplateMode.JAVASCRIPT);
resolver.setCharacterEncoding(UTF8);
resolver.setCheckExistence(true);
resolver.setCacheable(this.properties.isCache());
return resolver;
}
}
And the sample controller:
#Controller
public class JavascriptController {
#RequestMapping(method = RequestMethod.GET, value = "/js/test.js")
public String testjs() {
return "test.js";
}
}
The HTML view controllers remain unchanged.
I have set up spring 4.3.1 with Hibernate 5.1.0 and Jackson 2.7.5
I had some lazy init Exceptions because the Jackson ObjectMapper tries to convert my Objects to late when I am out of the Transactional Service.
Therefore I have read the Hibernate5Module for Jackson.
After adding the Module I do not get lazy Exceptions BUT all #JsonView Annotations are ignored and my lazy collections are 'null'
public class SpringWebConfig extends WebMvcConfigurerAdapter {
...
#Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
for (HttpMessageConverter<?> converter : converters) {
if (converter instanceof org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) {
ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
mapper.registerModule(new Hibernate5Module());
}
}
}
}
Is there anything I am doing wrong?
The Hibernate5Module should initialize the lazy collections ...
By creating your own ObjectMapper, you're overriding the one Spring Boot would set up, which would include a bunch of useful modules, such as Jdk8 module.
What you should do instead, is just add the Hibernate5() module to the Application Context and Spring Boot will automatically add it to the ObjectMapper that it sets up. Like this in any #Configuration class:
#Bean
public Hibernate5Module hibernate5Module() {
return new Hibernate5Module();
}
Got it to work with the following
#EnableWebMvc
#Configuration
#ComponentScan({ "..." })
public class SpringWebConfig extends WebMvcConfigurerAdapter {
#Autowired
SessionFactory sf;
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Hibernate5Module module = new Hibernate5Module(sf);
module.disable(Feature.USE_TRANSIENT_ANNOTATION);
module.enable(Feature.FORCE_LAZY_LOADING);
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.modulesToInstall(module);
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
I manage to make it work with the below implementation
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Hibernate5Module module = new Hibernate5Module(); // or Hibernate4Module ... depends on hibernate version you are using
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
converters.add(new MappingJackson2HttpMessageConverter(mapper));
}
jackson-datatype-hibernate5 bring many solutions but there are some default configurations as well.
Please have a look on
Below is the configuration I did as per my project requirements.
#Bean
public Hibernate5Module hibernateModule() {
Hibernate5Module module = new Hibernate5Module();
module.disable(Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION);
module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
return module;
}
I am trying to prototype a Spring Boot application. I'm coming from a Guice JAX-RS application, so I prefer the standard JAX-RS annotations to Spring MVC. I've gotten Jetty up and serving:
#Configuration
#Import({ResteasyBootstrap.class, SpringBeanProcessorServletAware.class, HttpServletDispatcher.class})
public class EmbeddedJetty {
#Bean
#Singleton
public EmbeddedServletContainerFactory servletContainer() {
JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory();
factory.setPort(9000);
factory.setSessionTimeout(10, TimeUnit.MINUTES);
return factory;
}
}
However, I just can't figure out how to get RESTEasy hooked up correctly. With the above SpringBeanProcessorServletAware it bails, seemingly the ServletContext is not injected through ServletContextAware before it ends up being used:
java.lang.NullPointerException: null
at org.jboss.resteasy.plugins.spring.SpringBeanProcessorServletAware.getRegistry(SpringBeanProcessorServletAware.java:30)
at org.jboss.resteasy.plugins.spring.SpringBeanProcessor.postProcessBeanFactory(SpringBeanProcessor.java:247)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284)
at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:680)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
I also tried using the SpringContextLoaderListener, but that seems to conflict with the spring-boot AnnotationConfigEmbeddedWebApplicationContext class.
I'm using spring-boot 1.3.3 and spring-framework 4.3.0.rc1
The other answer won't have your resources as spring beans, this autoconfiguration will integrate them properly:
The Configuration class:
#Configuration
#ConditionalOnWebApplication
public class RestEasyAutoConfigurer {
private Environment environment;
#Bean(name = "resteasyDispatcher")
public ServletRegistrationBean resteasyServletRegistration() {
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HttpServletDispatcher(), getPrefix()
+ "/*");
registrationBean.setInitParameters(ImmutableMap.of("resteasy.servlet.mapping.prefix", "/rs/")); // set prefix here
registrationBean.setLoadOnStartup(1);
return registrationBean;
}
#Bean(destroyMethod = "cleanup")
public static RestEasySpringInitializer restEasySpringInitializer() {
return new RestEasySpringInitializer();
}
#Bean
// use Spring Boot configured Jackson
public CustomResteasyJackson2Provider jackson2Provider(ObjectMapper mapper) {
return new CustomResteasyJackson2Provider(mapper);
}
public static class RestEasySpringInitializer
implements
ServletContextInitializer,
ApplicationContextAware,
BeanFactoryPostProcessor {
private ResteasyDeployment deployment;
private ConfigurableApplicationContext applicationContext;
private ConfigurableListableBeanFactory beanFactory;
public void cleanup() {
deployment.stop();
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
ListenerBootstrap config = new ListenerBootstrap(servletContext);
deployment = config.createDeployment();
deployment.start();
servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory());
servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher());
servletContext.setAttribute(Registry.class.getName(), deployment.getRegistry());
SpringBeanProcessor processor = new SpringBeanProcessor(deployment.getDispatcher(),
deployment.getRegistry(), deployment.getProviderFactory());
processor.postProcessBeanFactory(beanFactory);
applicationContext.addApplicationListener(processor);
}
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
}
And the Jackson provider:
#Provider
#Consumes({"application/*+json", "text/json"})
#Produces({"application/*+json", "text/json"})
public class CustomResteasyJackson2Provider extends ResteasyJackson2Provider {
private ObjectMapper mapper;
public CustomResteasyJackson2Provider(ObjectMapper mapper) {
this.mapper = mapper;
}
#Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
return Optional.ofNullable(_mapperConfig.getConfiguredMapper()).orElse(mapper);
}
}
NOTE: this is a working configuration for Spring Boot 1.3.3 / RESTEasy 3.0.16
You can use RESTEasy Spring Boot starter. Here is how you do it:
Adding POM dependency
Add the Maven dependency below to your Spring Boot application pom file.
<dependency>
<groupId>com.paypal.springboot</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.1.1-RELEASE</version>
<scope>runtime</scope>
</dependency>
Registering JAX-RS application classes
Just define your JAX-RS application class (a subclass of Application) as a Spring bean, and it will be automatically registered. See the example below. See section JAX-RS application registration methods in How to use RESTEasy Spring Boot Starter for further information.
package com.test;
import org.springframework.stereotype.Component;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#Component
#ApplicationPath("/sample-app/")
public class JaxrsApplication extends Application {
}
Registering JAX-RS resources and providers
Just define them as Spring beans, and they will be automatically registered. Notice that JAX-RS resources can be singleton or request scoped, while JAX-RS providers must be singletons.
Further information at the project GitHub page.
Here is fully working example.
First, a sample JAX-RS endpoint:
#Path("/api")
public class SampleResource {
#GET
#Path("/sample")
#Produces(MediaType.APPLICATION_JSON)
public String getSample() {
return "Some JSON";
}
}
Next, a JAX-RS configuration class that loads all endpoints.
import javax.ws.rs.core.Application;
public class RestEasyConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(SampleRest.class);
return classes;
}
}
Finally, in your Spring configuration, initialize RESTEast filter and inform the framework about its existence.
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.jboss.resteasy.plugins.server.servlet.FilterDispatcher;
...
#Bean
public FilterRegistrationBean filterRegistrationBean() {
Map<String, String> initParams = new HashMap<>();
initParams.put("javax.ws.rs.Application", RestEasyConfig.class.getCanonicalName());
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new FilterDispatcher());
registrationBean.setInitParameters(initParams);
return registrationBean;
}
Your endpoint should be up and running. If you are missing the FilterDispatcher class on your class path, add the resteasy-jaxrs library to your build descriptor.
In my Spring-Boot Web Application project I'm using Spring Cache to implement caching. Cache can be enabled/disabled by configuration key defined in application.yml. I already have existing test cases where tests are written assuming there is no cache. So by default in my integration-test profile caching is disabled and I initialize NoOpCacheManager and all my tests work.
#Profile(value = { "default", "production", "integration-test" })
#Configuration
#EnableCaching(mode = AdviceMode.ASPECTJ)
public class CacheBeanConfig extends CachingConfigurerSupport {
#Autowired
private CacheConfig cacheConfig;
#Bean
#Override
public CacheManager cacheManager() {
if (cacheConfig.isEnabled()) {
System.out.println("****************Couchbase CacheBeanTestsConfig cache init.**********************");
Map<String, DeclaraCouchbaseTemplate> cacheCouchTemplateMap = Maps.newHashMap();
Map<String, Integer> cacheTtlMap = Maps.newHashMap();
for (CacheConfig.CacheConfigParam cacheParam : cacheConfig.getCaches()) {
try {
cacheCouchTemplateMap.put(cacheParam.getName(),
couchbaseManager.getCouchbaseTemplate(cacheParam.getName()));
cacheTtlMap.put(cacheParam.getName(), cacheParam.getTtl());
} catch (IOException | URISyntaxException e) {
throw new FaultException("Unable to get couchbase template.");
}
}
return new CouchbaseCacheManager(cacheCouchTemplateMap, cacheTtlMap, metricRegistry);
} else {
System.out.println("****************NoOp CacheBeanTestsConfig cache init.**********************");
NoOpCacheManager noopCacheManager = new NoOpCacheManager();
return noopCacheManager;
}
}
}
I also want to write tests for verification of Caching functionality. I created a CachedControllerTest class where all the cache specific tests are written.
Problem is when I run
mvn test -Dtest=CachedControllersTest -Dspring.profiles.active=integration-test
All the tests in CachedControllerTest class are failing because cache manager is initialized with NoOpCacheManager even though I enabled the caching in the bean function.
I tried to create a separate profile for CachedControllerTest and it still fails because once cacheManager bean is initialized it is not getting reset.
mvn test -Dtest=CachedControllersTest -Dspring.profiles.active=integration-test,integration-cache-test
Here is my CachedControllerTest class
#ActiveProfiles("integration-cache-test")
#DirtiesContext
public class CachedControllersTest extends AbstractRestControllerTest {
#Configuration
#EnableCaching(mode = AdviceMode.ASPECTJ)
#Profile("integration-cache-test")
public static class CachedControllerTestsBeanConfig {
#Autowired
private CouchbaseManager couchbaseManager;
#Autowired
private CacheConfig cacheConfig;
#Autowired
private MetricRegistry metricRegistry;
#Autowired
GlobalApplicationConfig globalAppConfig;
#Bean
public CacheManager cacheManager() {
System.out.println("**************** CachedControllerTestsBeanConfig EnabledCaching**********************");
cacheConfig.setEnabled(true);
if (cacheConfig.isEnabled()) {
System.out.println("****************Couchbase CachedControllerTestsBeanConfig cache init.**********************");
Map<String, DeclaraCouchbaseTemplate> cacheCouchTemplateMap = Maps.newHashMap();
Map<String, Integer> cacheTtlMap = Maps.newHashMap();
for (CacheConfig.CacheConfigParam cacheParam : cacheConfig.getCaches()) {
try {
cacheCouchTemplateMap.put(cacheParam.getName(),
couchbaseManager.getCouchbaseTemplate(cacheParam.getName()));
cacheTtlMap.put(cacheParam.getName(), cacheParam.getTtl());
} catch (IOException | URISyntaxException e) {
throw new FaultException("Unable to get couchbase template.");
}
}
return new CouchbaseCacheManager(cacheCouchTemplateMap, cacheTtlMap, metricRegistry);
} else {
System.out.println("****************NoOp CachedControllerTestsBeanConfig cache init.**********************");
NoOpCacheManager noopCacheManager = new NoOpCacheManager();
return noopCacheManager;
}
}
#Bean(name = "mtlKeyGenerator")
public KeyGenerator keyGenerator() {
System.out.println("****************CachedControllerTestsBeanConfig mtlKeyGenerator.**********************");
return new MultiTenantKeyGenerator(globalAppConfig.getTenantId());
}
#Bean(name = CacheManagementConfigUtils.CACHE_ASPECT_BEAN_NAME)
#Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AnnotationGroupCacheAspect cacheAspect() {
AnnotationGroupCacheAspect cacheAspect = AnnotationGroupCacheAspect.aspectOf();
CacheManager cacheManager = (CacheManager) StaticContextHolder.getApplicationContext().getBean("cacheManager");
cacheAspect.setCacheManager(cacheManager);
KeyGenerator keyGenerator = (KeyGenerator) StaticContextHolder.getApplicationContext().getBean("mtlKeyGenerator");
cacheAspect.setKeyGenerator(keyGenerator);
return cacheAspect;
}
}
#Component
public static class StaticContextHolder implements ApplicationContextAware {
private static ApplicationContext appContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
appContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return appContext;
}
}
}
application.yml
spring:
profiles: integration-test
cache:
enabled: false
---
spring:
profiles: integration-cache-test
cache:
enabled: false
My requirement is to reinitialize the cacheManage for each Test Class and CacheConfig is the bean which I want to modify at the runtime so that appropriate CacheManager can be initialized.
In isolation if I run the CachedControllerTest class tests they all pass because there is no other Test Class run before that which would have initialized the cacheManager to NoOpCacheManager.
Thanks in advance for any help/suggestion to make this situation work.
Edit 1
Based on the suggestion by Sam, Added #ActiveProfiles.
Edit 2
AbstractRestControllerTest Class Definition
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
public class AbstractRestControllerTest {
}
#Profile has zero effect on a test class.
To set the active bean definition profiles for an integration test, you need to use #ActiveProfiles from the spring-testmodule.
Consult the Context configuration with environment profiles section of the Spring Reference Manual for details.
Also, CachedControllerTestsBeanConfig must be annotated with #Configuration not #Component.
Regards,
Sam (author of the Spring TestContext Framework)