Are spring-boot-starter-data-jpa and Liquibase incompatible? - spring-boot

I tried to setup a new Spring Boot 2.4.3 project and I want to include Liquibase as well as Spring Data JPA.
To achieve this I use the following dependencies in my POM:
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>${liquibase.version}</version>
</dependency>
or...
<dependency>
<groupId>org.liquibase.ext</groupId>
<artifactId>liquibase-hibernate5</artifactId>
<version>${liquibase.version}</version>
</dependency>
...respectively and
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
with
<kotlin.version>1.4.31</kotlin.version>
<liquibase.version>4.3.1</liquibase.version>
<hibernate.version>5.4.29.Final</hibernate.version>
Yet, in the beginning, I don't have any DB setup so far and in application.yaml you can find:
server:
port: 8080
spring:
liquibase:
change-log: classpath:db/changelog/db.changelog.yml
wherbey db.changelog.yml is empty.
A Maven install using the spring-boot-starter-data-jpa dependency results in:
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]: Invocation of init method failed; nested exception is
liquibase.exception.ChangeLogParseException: Empty file classpath:db/changelog/db.changelog.yml
Caused by: liquibase.exception.ChangeLogParseException: Empty file classpath:db/changelog/db.changelog.yml
while when commenting out this dependency the build succeeds.

I found out that the empty db.changelog.yml file must contain at least:
databaseChangeLog:
- changeset:
although on https://docs.liquibase.com/concepts/basic/changelog.html an example is given that an empty changelog.yaml file needs to look like:
databaseChangeLog:
, but this results in a BeanCreationException:
Caused by: liquibase.exception.ChangeLogParseException: Could not find databaseChangeLog node

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.

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>

ClassNotFoundException: DirectoryService with apacheds-all already included

I am implemented LDAP authentication in my Spring Boot Application. The dependencies added are as follows:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-all</artifactId>
</dependency>
However I am still getting following ClassNotFoundException:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain'
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]
Caused by: java.lang.NoClassDefFoundError: org/apache/directory/server/core/DirectoryService
Caused by: java.lang.ClassNotFoundException: org.apache.directory.server.core.DirectoryService
My maven dependency tree clearly shows apacheds-all is added successfully.
Why am I still getting this error?
Spring Security doesn't support Apache DS 2.0. Instead, you need to use 1.5.5. Also, note that later 1.5.x versions are not supported due to breaking API changes.

Error while deploying Spring Batch Application - java.lang.NoClassDefFoundError: org/codehaus/jettison/mapped/MappedXMLOutputFactory

I am stuck with this error from last few days , while loading the spring batch application,it keep on giving error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jobRepository' defined in ServletContext resource [/WEB-INF/classes/spring/batch/jobs/config/context.xml]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: org/codehaus/jettison/mapped/MappedXMLOutputFactory
I have added jettison to my pom and here below my pom file looks like
org.codehaus.jettison
jettison
1.3.2
org.springframework
spring-webmvc
${spring.version}
org.springframework
spring-oxm
${spring.version}
org.springframework.batch
spring-batch-test
${spring.batch.version}
jettison
org.codehaus.jettison
pom.xml should have dependency like :
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>1.3.2</version>
</dependency>
Also, do you see jettision-1.3.2.jar in your maven dependecies?
if you are using eclipse, ctr+sft+t : are you able to see this class?

PhaseInterceptorChain and HttpServletRequest lead to AbstractEndpointFactory ClassNotFoundException

I need the ability to reliably get client IP address in CXF JAX-WS and so I added the following code to my web service:
Message message = PhaseInterceptorChain.getCurrentMessage();
HttpServletRequest request = (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
request.getRemoteAddr();
In order for the build to complete successfully, I had to add the following imports:
import javax.servlet.http.HttpServletRequest;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
And add the following dependencies to my pom.xml:
<dependency> <!-- PhaseInterceptorChain & Message -->
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-api</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.2.3</version>
</dependency>
<dependency> <!-- HttpServletRequest -->
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<!-- scope>provided</scope -->
</dependency>
But when I try to deploy the resulting successful(!) build, Tomcat (7.0.42) throws an exception and refuses to load the war file:
org.springframework.beans.factory.BeanDefinitionStoreException:
Unexpected exception parsing XML document from class path resource [beans.xml];
nested exception is org.springframework.beans.FatalBeanException:
Invalid NamespaceHandler class [org.apache.cxf.jaxws.spring.NamespaceHandler] for namespace [http://cxf.apache.org/jaxws]:
problem with handler class file or dependent class;
nested exception is java.lang.NoClassDefFoundError: org/apache/cxf/endpoint/AbstractEndpointFactory
...
Caused by: org.springframework.beans.FatalBeanException:
Invalid NamespaceHandler class [org.apache.cxf.jaxws.spring.NamespaceHandler]
for namespace [http://cxf.apache.org/jaxws]:
problem with handler class file or dependent class;
nested exception is java.lang.NoClassDefFoundError: org/apache/cxf/endpoint/AbstractEndpointFactory
...
Caused by: java.lang.ClassNotFoundException: org.apache.cxf.endpoint.AbstractEndpointFactory
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
Apparently, something is missing from my pom.xml that provides the necessary module at runtime. What am I missing?
Mystery solved. For the benefit of all I am providing the root cause of the problem and the solution:
The problem was in this line:
<version>2.4.0</version>
That is, cxf-api artifact's version did not match the CXF version throughout the project (and the pom.xml).
All I had to do to solve the problem was to change that line to:
<version>${cxf.version}</version>
Where cxf.version was defined earlier as 2.7.1.
Conclusion: CXF dependencies/packages/plugins versions must match throughout the pom.xml (or else you will get some "red herrings").

Resources