Problem with Thymeleaf dependencies of a SpringBoot application - java

In my SpringBoot 3.0 application with Java 17 (built from Bootify.io), if I don't specify version for the following Thymeleaf dependencies, the application works correctly, and I can access http://localhost:8080/ without problem:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>
But, if I specify the following 2.X.X versions, I can no longer access http://localhost:8080/
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>2.5.3</version>
</dependency>
It fails with typicall:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Dec 29 09:52:09 CET 2022
There was an unexpected error (type=Not Found, status=404).
On the other hand, I can't specify 3.X.X dependencies, because running via GraalVM doesn't work. Also, if I don't specify version for Thymeleaf dependencies, execution from GraalVM fails
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>3.1.0</version>
</dependency>

You have 3.x as parent and giving 2.x in the starter and other dependencies is the problem. The idea of parent pom is to manage all spring related versions. if you define different dependency versions in your pom xml, it will break the compatibility. Therefore you will have errors or worse(compile problems like method not found).
You can see the parent pom in the pom xml like below
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.2</version>
<relativePath /><!-- lookup parent from repository -->
</parent>
Very rarely you may need to override versions of dependencies you can via properties check option 2

Related

ClassNotFoundException: org.apache.log4j.Priority when using Filenet APIs

I am using Spring Boot 2.7.2 to create a rest API that communicate with Filenet Content Engine using Filenet APIs and my pom file as follows :
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.test</groupId>
<artifactId>storage</artifactId>
<version>0.0.1</version>
<name>storage</name>
<description>Storage API</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.9</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Filenet Jars -->
<dependency>
<groupId>Jace</groupId>
<artifactId>Jace</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>stax-api</groupId>
<artifactId>stax-api</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>xlxpScanner</groupId>
<artifactId>xlxpScanner</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>xlxpScannerUtils</groupId>
<artifactId>xlxpScannerUtils</artifactId>
<version>5.2.1</version>
</dependency>
<!-- End Of Filenet Jars -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
<!--
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>MCI-maven</id>
<url>http://myhost/repository/maven-public/</url>
</repository>
</repositories>
</project>
The project compiles and starts up fine, but when trying to execute any filenet API I get a log4j error:
ClassNotFoundException: org.apache.log4j.Priority
That is because filenet APIs is using log4j1 classes.
The class is : com.filenet.apiimpl.util.BaseLogger.
The class imports are:
import com.filenet.api.exception.EngineRuntimeException;
import com.filenet.api.exception.ErrorLoggingLevel;
import com.filenet.api.util.UserContext;
import com.filenet.apiimpl.exception.ExceptionContext;
import java.util.Enumeration;
import org.apache.log4j.Category;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
The current solution is to add log4j 1.2.17 in pom file
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
When adding this the runtime exception disappears and everything works fine. But I only get the following warning on first time invoking filenet API:
log4j:WARN No appenders could be found for logger (filenet_error.api.com.filenet.apiimpl.util.ConfigValueLookup).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
[Perf Log] perflog.dir=null not found, auditor disabled
[Perf Log] No interval found. Auditor disabled.
Is there any better solution to this scenario rather than adding old log4j dependency ?
According to your actual pom.xml file, following the transitive dependencies spring-boot-starter-web and spring-boot-starter, you will end using spring-boot-starter-logging and its different dependent libraries, mainly based on logback and slf4j.
As you indicated, the Filenet APIs use Log4j 1.x.
The support for that version of Log4j was removed with the release of Spring Boot 2.x.
As a consequence, by default, the library will not give you support for that logging library.
That is the reason why you are facing the ClassNotFoundException: org.apache.log4j.Priority error.
In my opinion the solution you applied based on the inclusion of the log4j dependency itself is not a bad solution. A word of caution though:
the library has different vulnerabilities.
it was declared end-of-life in August of 2015.
the solution has the drawback of requiring a different configuration for the library and probably different output artifacts in which the log traces should be written.
As an alternative, you could use the Log4j 1.x bridge provided by Slf4j:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</dependency>
You can use the version 1.7.36 although it is managed by Spring Boot Starter Parent as well, so you don't need to provide a specific version for it.
Maybe there can be some caveats, some functionally used by the Filenet logger not implemented, but at first glance it seems to provide all the required stuff used by com.filenet.apiimpl.util.BaseLogger.
If that's the case, it will give you a better solution than using the log4j library, for the reasons explained, especially because it will allow you to integrate the Filenet loggers with your existing Spring Boot logging configuration and infrastructure.
Adding the following dependencies fixed my problem:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-logging', version: '2.7.1'
implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.17.1'
implementation group: 'org.slf4j', name: 'log4j-over-slf4j', version: '1.7.36'

How to use different spring module (spring-data-redis) version in specific spring boot version

I have a Spring boot project - its parent is spring-boot-starter-parent:2.1.9.RELEASE. I want to use the spring-data-redis with 2.2.0.RELEASE version (not the spring-boot-starter-data-redis because this does not support redis-streams). Also I use Lettuce version io.lettuce:lettuce-core:5.2.0.RELEASE.
My pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
However, I get the following error when run, though the application has no compilation errors.
***************************
APPLICATION FAILED TO START
***************************
Description:
An attempt was made to call a method that does not exist. The attempt was made from the following location:
org.springframework.data.redis.repository.configuration.RedisRepositoryConfigurationExtension.createMappingConfigBeanDef(RedisRepositoryConfigurationExtension.java:168)
The following method did not exist:
org/springframework/data/repository/config/RepositoryConfigurationSource.getRequiredAttribute(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
The method's class, org.springframework.data.repository.config.RepositoryConfigurationSource, is available from the following locations:
jar:file:/Users/user1/.m2/repository/org/springframework/data/spring-data-commons/2.1.11.RELEASE/spring-data-commons-2.1.11.RELEASE.jar!/org/springframework/data/repository/config/RepositoryConfigurationSource.class
It was loaded from the following location:
file:/Users/user1/.m2/repository/org/springframework/data/spring-data-commons/2.1.11.RELEASE/spring-data-commons-2.1.11.RELEASE.jar
Action:
Correct the classpath of your application so that it contains a single, compatible version of org.springframework.data.repository.config.RepositoryConfigurationSource
The spring-data-redis is resolved to 2.1.11.release version.
With the hint given by Dirk Deyne (who deleted those comments?), the spring-data-redis version can be overriden with the expected version like this
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
Having got other dependency issues because of this (error in question) specific version, have to add other libraries versions too, in this case
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
and the
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>

Not able to add JPA dependency into spring-boot project

I am trying to add JPA Maven dependency to already created spring-boot project but I am getting following error:
Error: Could not find or load main class com.kame.demo.DemoApplication
When I remove it the error is gone.
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.196</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>8.5.32</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
application.properties
spring.mvc.view.prefix=/pages/
spring.mvc.view.suffix=.jsp
spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:navin
I tried to find answer online but none was solution for me.
Also tried to create > Spring starter project > an there immediately add JPA, Web and H2 but still same error.
I am using STS IDE, is something related to it maybe?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Is itself a demo project with an extending SpringBoot class as the main class of your project. But this dependency does the same :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
So there is high chances that both will clash...
The solution is to import the correct dependency for jpa and not the spring boot starter jpa dependency.
EDIT
This one might do the trick instead :
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
But I recommend you read the official documents to get started properly : https://docs.spring.io/spring-data/jpa/docs/2.1.0.RC2/reference/html/
I faced the same issue while I tried to add JPA dependency manually in POM.xml after creating Spring boot with Web only.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
Root cause of the problem:- JPA dependency jar was missing. verify:-
File->Project structure->Modules->Dependencies and you will not find any jar org.springframework.boot:spring-boot-starter-data-jpa:2.4.3 (I am using spring boot 2.4.3 but in your case version can be different)
Solution:-
Step 1
File -> Invalidate Caches / Restart... and choosing the Invalidate and Restart option fixed the issue. can be a stale cache issue
Step 2
Under IntelliJ Idea open POM.xml right click-> Maven-> Reload project.
Maven will download the JPA dependency jar and will add into the project. Verify if JPA jar is added or not.
Step 3
Selecting File -> Invalidate Caches / Restart... and choosing the Invalidate and Restart option fixed the issue.
NB:- If you are not using ItellIj id then please force Maven to download dependency (for step2)

mssql-jdbc version 6.2.2.jre8 dependency results in version 6.1.0.jre7 in war

I have the following dependency in my Maven project
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.2.2.jre8</version>
<!-- Exclude unused Azure dependencies -->
<exclusions>
<exclusion>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
</exclusion>
<exclusion>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
</exclusion>
</exclusions>
</dependency>
I am using the newest non-preview mssql-jdbc release in Maven here
https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc
However when I run mvn clean package my resulting war file has mssql-jdbc-6.1.0.jre7.jar in WEB-INF/lib instead of the expected mssql-jdbc-6.2.2.jre8.jar. I have tried clearing my local .m2 repository and repackaging but that did not help. It is worth noting that 6.1.0.jre7 is actually the oldest version out there, so my guess is that for some reason it cannot find the newest one and is reverting to the oldest? I'm stuck.
I encountered same problem, and I am using Spring Boot 1.5.x.
The root cause is: Spring Boot(1.5.x) specified the version of "6.1.0.jre7".
Solution is: specify your version in the main module which contains Spring boot Application.
Previous part of my dependencies:
Sub module 1:
<groupId>com.my.company</groupId>
<artifactId>sub-module1</artifactId>
<version>1.0</version>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.1.3.jre8-preview</version>
</dependency>
Main module, which contains Spring boot Application:
<dependency>
<groupId>com.my.company</groupId>
<artifactId>sub-module1</artifactId>
<version>1.0</version>
</dependency>
And I found Main module boot.jar included "mssql-jdbc-6.1.0.jre7.jar".
Finally I found the version is specified in "spring-boot-dependencies" which is the parent of "spring-boot-parent".
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.16.RELEASE</version>
<mssql-jdbc.version>6.1.0.jre7</mssql-jdbc.version>
Solution:
Specify the version in main module:
<dependency>
<groupId>com.my.company</groupId>
<artifactId>sub-module1</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.1.3.jre8-preview</version>
</dependency>
Checked the result by mvn denpendency:tree, it's ok

How to determine the <parent> dependency for a set of springframework dependencies

I like to know if below is possible and how.
I was following a tutorial for spring boot and it was mentioned there we can have a parent dependency.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
And then define the dependencies without the version number.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
This will add the dependencies version 1.5.6.RELEASE of spring-boot-starter and spring-boot-starter-web in to the projects dependencies.
Just like that I want to find what is the <parent> code snippet for the following dependencies I need to add in to a new project.
Dependencies in <groupId>org.springframework</groupId>. I need to use the version 4.3.9.RELEASE.
spring-context
spring-jdbc
spring-test
Thanks!
If you are using Spring Boot then these three dependencies will be provided for you by the following starters:
spring-test will be provided by spring-boot-starter-test
spring-context will be provided by spring-boot-starter-data-jpa
spring-jdbc will be provided by spring-boot-starter-jdbc
So, with the following parent:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
</parent>
... if you add these dependencies:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
... then you will get
spring-context
spring-jdbc
spring-test
However, Spring Boot 1.5.6.RELEASE depends on v4.3.10.RELEASE of those core Spring libraries not 4.3.9.RELEASE as suggested in your question. Typically, you would accept Spring's curation of dependencies so if Sping provides 4.3.10.RELEASE then either (a) you should use that version or (b) downgrade Spring Boot toa version which provides 4.3.9.RELEASE.
Read on for details on how to identify the correct starter for a given curated library ...
The spring-boot-starter-parent is a special starter that provides useful Maven defaults and a dependency-management section which defines numerous dependencies which you might want to use in your POM. These dependencies are often referred to as "curated" or "blessed" and since they are defined in a dependency-management section somewhere in the maven hierarchy you can refer to them in your POM without a version tag (i.e. they inherit the version from the dependency-management section entry.)
You can see the spring-boot-starter-parent POM here and peeking inside you can see that it references the spring-boot-dependencies POM here.
Looking at your question you mentioned that you can declare a dependency like so ...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
... this is because the spring-boot-dependencies POM declares the following:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${revision}</version>
</dependency>
So, the parent and the starters are just a means of wrapping up dependency declarations and making them easier for application developers to use. The Spring docs summarise this as:
Starters are a set of convenient dependency descriptors that you can include in your application. You get a one-stop shop for all the Spring and related technologies that you need without having to hunt through sample code and copy-paste loads of dependency descriptors. For example, if you want to get started using Spring and JPA for database access, include the spring-boot-starter-data-jpa dependency in your project.
However, this does not mean that all dependencies must be declared via parents or starters so, if you are not using Spring Boot then you can declare a dependency without using a parent or a starter and what you have described in your question (declaring dependencies on 3 core Spring libraries) can be safely covered by simply depending on those 3 libraries explicitly. For example, just add the following to your your pom.xml:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>4.3.9.RELEASE</version>
<scope>test</scope>
</dependency>
Since you are going though the tutorials I'm assuming you are new to spring.
The folks at spring were nice enough to setup a site that generates projects.
It is very easy to use. I recommend trying that while learning. Download a few apps with the dependencies you want and look at how they are set up.
Once you are comfortable and want to dive deeper, read #glytching's answer again, it is very good.
Use spring-framework-bom if you don't use Spring Boot and need Spring Framework dependencies only:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.3.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
In such case dependency would be without version was specified:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
Also, yet another option exists if you use Spring Boot but you don't want to use spring-boot-starter-parent as parent artifact:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
See Spring Boot docs for more details. An important note from the docs:
Each release of Spring Boot is associated with a base version of the Spring Framework so we highly recommend you to not specify its version on your own.
It means that you should use Spring Framework version is defined for Spring Boot.

Categories