Ali Akbarpour
Ali Akbarpour

Reputation: 964

Adding JAR file as dependency to project without its related JARs

We have file payment.jar that developed with Spring Framework 3.1.2 . We need to use it as a dependency on a new project that its version is Spring Framework 5.x .

Problem: When payment.jar used as a dependency, the payment.jar transitive dependencies add to project class-path so in cause conflicting Spring Framework 3 and Spring Framework 5.

I tried solutions:

  1. big fat jar:

create-an-executable-jar-with-dependencies-using-maven

there is no success, the fat JAR, adds Spring Framework 3 to project. (what I am doing wrong!)

  1. excluding payment Spring Framework 3.1.2 dependency in new project:

because of using spring-ibatis implementation in payment.jar it is not worked. Spring Framework new versions do not support ibatis.

Error:

Caused by: java.lang.ClassNotFoundException: org.springframework.orm.ibatis.support.SqlMapClientDaoSupport

my requirement: I need to use payment.jar (with Spring Framework 3.1.2) as a dependency on new project with Spring Framework 5.x without problem mentioned above.

Upvotes: 4

Views: 1235

Answers (6)

Carlos Cavero
Carlos Cavero

Reputation: 3196

The ideal solution would be to update everything to Spring 5 or deploy payment.jar separately as a microservice as others mentioned. But this is not the core part of your question, maybe you have some unavoidable requirements. So as @tomer-shahar said the solution is to use maven shade plugin.

This kind of conflicts happen a lot when you use open source libraries sharing the same libraries but with different versions.

The maven shade plugin allows renaming/recolocating the packages selected avoiding conflicts within versions. The drawback is that some classes will be duplicated (so it is far from ideal). See the example below:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.0.0</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <finalName>spring321-payment-shaded</finalName>
        <relocations>
          <relocation>
            <pattern>spring.package</pattern>
            <shadedPattern>shaded.spring.package</shadedPattern>
          </relocation>
        </relocations>
        <artifactSet>
          <includes>
            <include>*:*</include>
          </includes>
        </artifactSet>
      </configuration>
    </execution>
  </executions>
</plugin>

And then add as dependency to the Spring 5 project this shaded library with all the renaming/rellocation done. I used this interesting article where all the details are fully described.

Upvotes: 1

Ankit Jindal
Ankit Jindal

Reputation: 21

The best option for this is to upgrade this manually. Even if you will do this with Spring 3 jar, you will land with a lot of issues while compiling and running.

Upvotes: 1

Tomer Shahar
Tomer Shahar

Reputation: 343

Though I have not done this with spring specifically, the general concept of what you are trying to accomplish is called shading.

https://softwareengineering.stackexchange.com/questions/297276/what-is-a-shaded-java-dependency

The reason the fat jar didn't work is because all jars were loaded to the classpath, and the wrong one will be chosen for at least on of the dependencies.

What you need to do is change the package name in both a dependency and the depending jar (in your case spring 3 and payment jar), so you basically end up with two pairs of dependencies that don't overlap.

This is relatively simple to do in maven and similar tools. See the link for more details.

Upvotes: 0

Vy Do
Vy Do

Reputation: 52746

Your wish

I need to use payment.jar (with Spring Framework 3.1.2) as a dependency on new project with Spring Framework 5.x without problem mentioned above.

You cannot do it. Because the mismatching of version of dependencies. It is not backward compatible between many things, many version of iBatis, Spring Framework, payment.jar and other dependencies.

You must upgrade it manually.

Upvotes: 2

xcesco
xcesco

Reputation: 4838

I suggest you to convert your jar in Spring 5 and MyBatis. I think it's the better solution in terms of mantenibility and compatibility. Migrate to iBatis to MyBatis does not a big problem, I think.

I had a working project that uses Spring 5 and My-Batis 3. I encountered some problem to configure it, but in the end, I solved everything. Just check the POM configuration and the Spring configuration.

POM configuration

In the following lines of code, you can read the project pom (I removed useless part of the file for your problem).

<?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 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>it.dummy</groupId>
    <artifactId>dummy</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>Dummy App</name>
    <url>http://maven.apache.org</url>

    <properties>
        <java-source.version>1.8</java-source.version>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.skip.tests>true</maven.skip.tests>

        <servlet-api.version>3.1.0</servlet-api.version>
        <spring.version>5.0.7.RELEASE</spring.version>
        <swagger.version>2.9.2</swagger.version>
        <jackson.version>2.9.6</jackson.version>
        <mybatis-spring>1.3.2</mybatis-spring>
        
        <junit.version>4.12</junit.version>
        <frontend-maven-plugin.version>1.4</frontend-maven-plugin.version>

        <mapstruct.version>1.2.0.Final</mapstruct.version>
    </properties>

    <dependencies>

        <!-- -->
        <!-- https://mvnrepository.com/artifact/org.mapstruct/mapstruct -->
        <!-- https://github.com/mapstruct/mapstruct -->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>${mapstruct.version}</version>
        </dependency>

        <!-- cucumber -->
        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.14.0</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-java -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-junit -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>1.2.5</version>
            <scope>test</scope>
        </dependency>


        <!-- test -->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/javax.servlet/servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>${servlet-api.version}</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-rest-core -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-rest-core</artifactId>
            <version>3.0.10.RELEASE</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>


        <!-- Spring Security Artifacts - START -->
        <!-- http://mvnrepository.com/artifact/org.springframework.security/spring-security-web%20 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- http://mvnrepository.com/artifact/org.springframework.security/spring-security-config%20 -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- Spring Security Artifacts - END -->


        <!-- Swagger - BEGIN -->
        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
        </dependency>


        <!-- Swagger - END -->

        <!-- json -->
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>${jackson.version}</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>${mybatis-spring}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.6</version>
        </dependency>


        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
            <type>jar</type>
        </dependency>
        
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.9</version>
        </dependency>
        
    </dependencies>
    
</project>

Just remember to check always the dependencies tree to avoid to have indesiderate Spring jars.

Dependencies tree

Spring configuration

I have different file for Spring configuration. I attach only the interesting one.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">


    <bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
        <property name="URL" value="jdbc:oracle:thin:@xxx:yyy:zzz" />
        <property name="user" value="aaa"/>
        <property name="password" value="bbb"/>
        <property name="connectionCachingEnabled" value="true" />
    </bean> 

    
    <bean id="transactionManagerNG" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="sqlSessionFactoryNG" class="org.mybatis.spring.SqlSessionFactoryBean" name="SqlSessionFactoryOrarioStandardDao">
        <property name="dataSource" ref="dataSource" />
        <!-- 1. Where is the xml for query's definitions -->
        <property name="mapperLocations" value="classpath:com/dummy/persistence/dao/*.xml" />
        
        <!-- 2. My-batis configuration -->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
        
        <!-- 3. My-batis type alias package -->
        <property name="typeAliasesPackage" value="com.dummy.persistence.model" />
    </bean>
    
    <!-- 4. needed to parse Java DAO interfaces -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="it.insiel.sanita.farmacieng.persistence.dao" />     
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryNG"/>
    </bean>
    
    <tx:annotation-driven/> 
</beans>

In the above Spring file you will find:

  • How I defined the location where put XML for SQL queries (comment 1)
  • How I use My-batis configuration (comment 2)
  • How I defined the type alias package (comment 3)
  • How I defined the DAO interfaces

Last but not least the My-batis configuration file mybatis-config.xml, that I put in the same folder of Spring configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- http://mybatis.org/dtd/ -->
<configuration>

    <settings>
        <setting name="logImpl" value="LOG4J"/>              
        <setting name="cacheEnabled" value="true"/>
        <setting name="defaultStatementTimeout" value="3000"/>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        
        <setting name="jdbcTypeForNull" value="NULL" />                
    </settings>
    
</configuration> 

Upvotes: 0

Stephen Savitzky
Stephen Savitzky

Reputation: 311

If the Spring versions are as incompatible as it sounds as though they are, you're probably going to have to recompile either the jar or the project so that they're using the same version of Spring.

If that's impossible (e.g. if you don't have source for the jar), you might be able to wrap the payment jar up in a microservice so that it's running in a different process, and talk to it via XML-RPC or SOAP.

Upvotes: 7

Related Questions