Autowire CacheManger (Caffeine & Ehcache) without using #SpringBootApplication - spring-boot

I have a common caching module which has spring boot starter cache (version 2.2.4.RELEASE) and for caching has dependencies of ehcache & caffeine. Below is the pom file
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
In this module, Autowired the CacheManger and has cache update & get method using spring cache.
#Autowired
private CacheManager cacheManager;
This module is added as dependency in the app1 which is springboot application and as per the property "spring.cache.type", when app1 starts it will initialize the respective cache
For caffeine cache
spring.cache.type=caffeine
spring.cache.caffeine.spec=maximumSize=10000
For Ehcache3
spring.cache.type=caffeine
spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider
spring.cache.jcache.config=classpath:ehcache.xml
This is all working fine for springboot application app1.
Now i am using the same caching module in app2 which has functionality same as app1 but it is not springboot application. In app2 using #Configuration , #ComponentScan to resolve the dependency. Now app2 is being used in app3 which is springboot application. All the other dependencies are resolved and working fine in app3 except the cacheManger. Getting the below error while running the app3
*\r\nAPPLICATION FAILED TO START\r\n***************************\r\n\r\nDescription:\r\n\r\nField cacheManager in commonCacheService required a bean of type 'org.springframework.cache.CacheManager' that could not be found.\r\n\r\nThe injection point has the following annotations:\r\n\t- #org.springframework.beans.factory.annotation.Autowired(required=true)\r\n\r\nThe following candidates were found but could not be injected:\r\n\t- Bean method 'cacheManager' in 'EhCacheCacheConfiguration' not loaded because #ConditionalOnClass did not find required class 'net.sf.ehcache.Cache'\r\n\t- Bean method 'cacheManager' in 'GenericCacheConfiguration' not loaded because Cache org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration unknown cache type\r\n\t- Bean method 'cacheManager' in 'JCacheCacheConfiguration' not loaded because Cache org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration unknown cache type\r\n\t- Bean method 'cacheManager' in 'NoOpCacheConfiguration' not loaded because Cache org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration unknown cache type\r\n\t- Bean method 'cacheManager' in 'SimpleCacheConfiguration' not loaded because Cache org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration unknown cache type\r\n\r\n\r\nAction:\r\n\r\nConsider revisiting the entries above or defining a bean of type 'org.springframework.cache.CacheManager' in your configuration.\r\n"}
It is working if i create bean in common cache module like below
#Bean
#ConditionalOnProperty(name="spring.cache.type", havingValue="caffeine")
#Primary
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder().maximumSize(125000));
return cacheManager;
}
But i want to avoid the bean creation in common module. Is there any annotation/configuration required in app2 (without changing app3 as don't have any update control on app3)so that it will also work in same way as it is working in app1 )?

I know it is quite late, but I faced the same issue. It was resolved by adding dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.1</version>
</dependency>
And add
#EnableCaching
in the SpringBootApplciation Class

Related

Tomcat 10, Java 17 - JavaMailSender cannot cast one of elements of java.lang.Object[]

After migrating application to Spring Boot 3 and Java 17 I tried to deploy it to Tomcat 10.1.x.
The deployment failed with exception:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'mailSender' defined in class path
resource [org/springframework/boot/autoconfig
ure/mail/MailSenderPropertiesConfiguration.class]: Failed to
instantiate [org.springframework.mail.javamail.JavaMailSenderImpl]:
Factory method 'mailSender' threw exception with message: arraycopy:
element type mismatch: can not cast one of the elements of
java.lang.Object[] to the type of the destination array,
jakarta.activation.MimeTypeRegistry
The issue turned out to be caused by CXF library having dependency on:
com.sun.activation:jakarta.activation.
The solution is to exclude it from cxf:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
Instead include directly the jakarta.activation-api as below:
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.1.1</version>
</dependency>
There might be other libraries with the same dependency in the application.
For above the approach with deploying application to webapps-javaee folder and allowing Tomcat to perform migration doesn't work.

Spring boot fails to start when add Kubernetes dependencies "The bean 'kubernetesPodUtils', defined in class path resource"

I trying to add Kubernetes to my project to use Service name rather than localhost. I added the below dependencies :
#AutoConfigureAfter
#EnableEurekaClient
#EnableFeignClients
#EnableDiscoveryClient
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-kubernetes-client-all -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-config</artifactId>
<version>1.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes</artifactId>
<version>1.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-discovery</artifactId>
<version>2.1.3</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-core</artifactId>
<version>1.1.10.RELEASE</version>
</dependency>
<!-- MicroServices -->
But I got the below error :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'kubernetesPodUtils', defined in class path resource [org/springframework/cloud/kubernetes/KubernetesAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/kubernetes/client/KubernetesClientAutoConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
2022-06-14 12:28:08.696 ERROR 1 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'kubernetesPodUtils', defined in class path resource [org/springframework/cloud/kubernetes/KubernetesAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [org/springframework/cloud/kubernetes/client/KubernetesClientAutoConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
Looks like KubernetesAutoConfiguration is going to be defined in multiple dependencies. Based on your need, try to identify the dependencies which are required. In your pom file you have spring-cloud-starter-kubernetes-client-all alongwith individual dependecies too.
https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#starters

Do Spring LDAP and Spring Cloud Consul work together?

I had a project with Spring LDAP in place. I am trying to put in Spring Consul into this project and have been facing issues with respect to it.
Here is the pom.xml :
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
Here is application properties :
#consul properties
spring.cloud.consul.config.format=PROPERTIES
spring.cloud.consul.discovery.healthCheckPath=/<root>/health
spring.cloud.consul.discovery.healthCheckInterval=15s
spring.application.name=<App_Name>
spring.profiles.active=dev
And I enabled discovery client using #EnableDiscoveryClient on SpringBootApplication class.
But, I am ending up with this error and the app never starts :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field ldapTemplate in com.<package>.config.LdapClient required a bean of type 'org.springframework.ldap.core.LdapTemplate' that could not be found.
- Bean method 'ldapTemplate' not loaded because #ConditionalOnClass did not find required class 'org.springframework.data.ldap.repository.LdapRepository'
Action:
Consider revisiting the conditions above or defining a bean of type 'org.springframework.ldap.core.LdapTemplate' in your configuration.
Disconnected from the target VM, address: '127.0.0.1:62703', transport: 'socket'
I figure it has something to do with autodiscovery of Ldap and introducing Consul is causing this issue, but, I am not able to pin-point the problem.
Can someone please help me resolve this issue?

Testing Neo4j with Spring Boot and embedded driver

Problem
I build an application using a Neo4j database. I like to test some custom Cypher queries using Spring Boot's #DataNeo4jTest annotation (see also Spring Boot Test - Neo4j), but I run in either one of the following problems:
The test tries to connect to a Neo4j instance using the BOLT driver.
The test fails to load the embedded driver.
Details
My dependencies are managed with Maven following the Spring Data Neo4j Reference Documentation. Section 10.3.1 of the SDN documentation explains:
By default, SDN will use the BOLT driver to connect to Neo4j and you don’t need to declare it as a separate dependency in your pom. If you want to use the embedded or HTTP drivers in your production application, you must add the following dependencies as well. (This dependency on the embedded driver is not required if you only want to use the embedded driver for testing. See the section on Testing below for more information).
Therefore, the relevant parts of my pom.xml are:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi=...>
...
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
...
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>3.3.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
...
</project>
My main/resources/application.yml is:
spring:
data:
neo4j:
uri: bolt://localhost
username: <username>
password: <password>
My test/resources/application.yml is:
spring.data.neo4j.uri: file:///neo4j.db
Without the test/resources/application.yml I get the following exception, which I assume is caused by using the BOLT driver:
org.springframework.transaction.CannotCreateTransactionException: Could not open Neo4j Session for transaction;
nested exception is org.neo4j.driver.v1.exceptions.AuthenticationException: The client is unauthorized due to authentication failure.
With the test/resources/application.yml I get the following exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'neo4jAuditionBeanFactoryPostProcessor': Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.class]: Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.neo4j.ogm.session.SessionFactory]: Factory method 'sessionFactory' threw exception;
nested exception is org.neo4j.ogm.exception.core.ConfigurationException: Could not load driver class org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver
Questions
Are there any dependencies missing?
Is the configuration wrong?
Does anyone have a link to a working example using the Spring Boot annotation #DataNeo4jTest?
Any suggestion is welcome.
I have found a solution to my problem. It seems as if the BOLT driver is used as default for testing as well - which is confusing given the Spring Data Neo4j (SDN) documentation. Finally, the pom.xml of the GitHub project movies-java-spring-data-neo4j helped me. I added the following test dependency to my pom.xml:
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>${neo4j-ogm.version}</version>
<scope>test</scope>
</dependency>
I kept the test/resources/application.yml but removed the line:
spring.data.neo4j.uri: file:///neo4j.db
Now, the test context starts with the embedded driver, and creates a temporary database file like file:/C:/Users/Me/AppData/Local/Temp/neo4j.db6943517458205762238/, which is awesome. I can get a clean database instance for every test method.
I hope this answer will help others, who have the same problem. I'm happy to provide more details if necessary.
#DataNeo4JTest works great with Spring Boot 2.x.
Example Test:
#RunWith(SpringRunner.class)
#DataNeo4jTest
public class WidgetRepositoryTest {
#Autowired
private WidgetRepository repository;
private Widget widget;
#Before
public void setUp() {
widget = WidgetTestData.builder().build();
}
#Test
public void itShouldSaveAndRetrieve() {
final Widget saved = repository.save(widget);
assertThat(saved.getId()).isNotNull();
assertThat(saved.getName()).isEqualTo(widget.getName());
final Optional<Widget> found = repository.findById(saved.getId());
assertThat(found).hasValueSatisfying(w-> {
assertThat(w.getId()).isEqualTo(saved.getId());
assertThat(w.getName()).isEqualTo(saved.getName());
});
}
}
The Neo4J-related dependencies in my Maven POM:
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

Spring Data makes spring unable to find JAXRS's #Provider?

I am using Spring + Jersey to build an API service .
Recently , I try to incorporate Spring Data to my server .
I haven't truly use any Repositories in my running code , just add one line in my app.xml :
<jpa:repositories base-package="destiny.web" entity-manager-factory-ref="entityManagerFactoryApp" />
But ! I notice my API not working , complaining "A message body writer for Java class xxx , and Java type class xxx , and MIME media type application/json was not found"
If I remove the "jpa:repositories ..." line in my xml , everything works fine !
and , all provider classes are registered by spring :
{http://*:8080-1} Registering Spring bean, apiResultJsonWriter, of type destiny.web.api.ApiResultJsonWriter as a provider class
{http://*:8080-1} Registering Spring bean, webApi, of type destiny.web.api.WebApi as a root resource class
{http://*:8080-1} Initiating Jersey application, version 'Jersey: 1.8 06/24/2011 12:17 PM'
But , if I add "jpa:repositories..." line in my XML , only "root resources class" are registered :
{http://*:8080-1} CDI support is enabled
{http://*:8080-1} Using default applicationContext
{http://*:8080-1} Registering Spring bean, webApi, of type destiny.web.api.WebApi as a root resource class
{http://*:8080-1} Initiating Jersey application, version 'Jersey: 1.8 06/24/2011 12:17 PM'
All JAXRS's #Provider(s) are missing !
I don't know if it is Spring-Data's bug ?
And how to solve it ?
environment :
spring-3.1
jersey-core-1.8.jar
jersey-server-1.8.jar
jersey-spring-1.8.jar
spring-data-jpa-1.0.3.RELEASE.jar
spring-data-commons-core-1.1.0.RELEASE.jar
server : resin-4.0.25
Related dependencies :
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-spring</artifactId>
<version>1.8</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.0.3.RELEASE</version>
</dependency>
( I tried to add jersey-json , but still not working )
You need to register the packages that contain classes annotated with #Provider
in Jersey 2 this is done via by calling the packages method in your ResourceConfig class.
I believe there is also a basepackages attribue you can put on the servlet. See here Autodiscover JAX-RS resources with CXF in a Spring application

Resources