The conflict between bcprov-jdk15to18 and other bcprov version jar packages (different versions of jars are compatible) is resolved, and the conflict with Dongfangtong bcprov-jdk15on.jar is resolved

Foreword

The project needs to integrate a new SDK for service calls. It was developed and debugged locally using Tomcat. However, when updated to the server, it failed and the service could not be started. Error SecurityException: JCE cannot authenticate the provider BC.
After replacing the jar with the same version as Dongfangtong, another error was reported: java.lang.SecurityException class "org.bouncycastle.crypto.digests.GeneralDigest"'s signer information does not match signer information of other classes in the same package, the version is too low and does not meet the use of sdk

Solution ideas

After trying different solutions

Method Result
Downgrade the jars that the project depends on

td>

Project error
Replacing Dongfangtong jar Various weird errors
Downgrade the jar version that the sdk depends on to be consistent with the jar version of Dongfangtong The amount of modification is relatively large

At the same time, I also saw the use of maven packaging to solve the [Review] bcprov-jdk16 package conflict problem (different versions of jars are compatible) and the use of maven-shade-plugin, but unfortunately I can’t use it. At the same time, it provided me with an idea: Change the package name

Once you have the idea, you can look online to see if there are any useful tools, and finally you find a packaging replacement tool: jarjar.jar

Detailed introduction to replacing JAR package name with jarjar.jar

  • Get jar
    https://mvnrepository.com/artifact/com.googlecode.jarjar/jarjar This jar version is relatively old and cannot be processed for annotated jar packages, and the function features of java8 cannot be effectively processed.
    https://mvnrepository.com/artifact/com.eed3si9n.jarjar/jarjar-assembly/1.13.1The version is relatively new, and the usage rules are similar to the older jarjar, so feel free to use it
    Use java -jar jarjar-1.3.jar to view help
houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/testtt
$ java -jar jarjar-1.3.jar
Jar Jar Links - A tool for repackaging and embedding Java libraries
Copyright 2007 Google Inc.

Command line usage:

  java -jar jarjar.jar [help]

    Print this help message.

  java -jar jarjar.jar strings <cp>

    Dump all string literals in classpath <cp>. If the class has debug information, the line number will be included.

  java -jar jarjar.jar find <level> <cp1> [<cp2>]

    Prints the dependencies in classpath <cp1> on classpath <cp2>. If <cp2> is omitted, <cp1> is used for both parameters.

    The level parameter must be "class" or "jar". The former prints the dependencies between various classes,
While the latter only prints jar->jar dependencies. "jar" here is actually any classpath component,
Can be a jar file, zip file or parent directory (see below).

  java -jar jarjar.jar process <rulesFile> <inJar> <outJar>

   Convert the jar file and write the new jar file. Anything with. Existing files named will be deleted.
   Transformations are defined by a set of rules in the file specified by the rules parameter (see below).

Classpath format:

  The classpath parameter is a colon- or semicolon-separated set of directories, jar files, or zip files (depending on the platform). For more details, see the following pages:
  http://java.sun.com/j2se/1.5.0/docs/tooldocs/solaris/classpath.html

  Mustang-style wildcard support:
  http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6268383

Rule file format:

  The rules file is a text file with one rule per line. Leading and trailing spaces are ignored. There are three types of rules:

    rule <pattern> <result>
    zap <pattern>
    keep <pattern>

  Standard rules ("rules") are used for renaming classes. All references to the renamed class will also be updated.
  If a class name matches multiple rules, only the first rule is applied.

  <pattern> is the class name with optional wildcard characters. "**" will match any valid class name substring. To match a single
To wrap a component (to exclude "." from matching), a single "*" can be used instead.

  <result> is a class name that optionally references a substring matched by a wildcard. There is a number reference for each "*" or "**" in <pattern>, from left to right: "@1", "@2", etc.
  A special "@0" reference contains the entire matching class name.

  The "zap" rule will cause any matching classes to be removed from the generated jar file. All zap rules are processed before renaming the rules.

  The "keep" rule marks all matching classes as "roots". If any keep rules are defined, then when writing the output jar,
  All classes that are not accessible from the root via dependency analysis will be discarded. This is the final step after renaming and deleting.

Use jarjar to modify jars such as sdk and bcprov

Write rule.txt

rule org.bouncycastle.** shade.bouncycastle.@1

Replace package and import

houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/testtt
$ java -jar jarjar-1.3.jar process rule.txt bcprov-jdk15to18-1.67.jar shade-bcprov-jdk15to18-1.67.jar
houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/testtt
$ java -jar jarjar-1.3.jar process rule.txt bcpkix-jdk15to18-1.67.jar shade-bcpkix-jdk15to18-1.67.jar
houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/testtt
$ java -jar jarjar-1.3.jar process rule.txt send-api-sdk-1.2.1.jar newsend-api-sdk-1.2.1.jar

The final decompilation result is as follows


It can be found that package and import have been replaced. Replace the replaced sdk and bcprov online, delete the original conflicting jars, and the service is normal. This is the end of the story~~

Expansion: If there are personalized modifications, you can also use the incremental update method (generally not used, this is just a starting point)

Note: If A.jar only depends on B.jar and you just want to bind the dependencies of A and B, you can use the above method to modify both A.jar and B.jar to meet the needs. The following personalized modification scenario is not only for If the dependencies are modified, the logic in them will also be modified. You can use the Java feature of overwriting classes with the same name in the same package to recompile a certain class.
Replace the encrypted JAR after the class call in the original sdk jar replaces the package name. For details, you can move to “Incremental update method of Jar package in Java project, unzip and modify the files in the Jar package and then re-type it into a Jar package”

houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads
$ cd aaaaaaa/

houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/aaaaaaa
$ll
total 60
-rw-r--r-- 1 houzw 197121 58060 Oct 7 17:29 send-api-sdk-1.2.1.jar

houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/aaaaaaa
$ jar -xvf send-api-sdk-1.2.1.jar
  ?: META-INF/
  : META-INF/MANIFEST.MF
  .
  .
  .
houzw@DESKTOP-J9FIROU MINGW64 ~/Downloads/aaaaaaa
$ jar -uvf0 send-api-sdk-1.2.1.jar cn

Keep the replaced class and delete other irrelevant files. Execute jar -uvf0 xxx.jar file folder and use folder to pair jar file Make incremental updates.
After updating, decompile and take a look, and you will see that the new method is indeed called.
Decompile
After starting the online service again, no error was reported and the service call was normal. Finished, scatter flowers~~

Summary

When there is a jar package conflict. And there is a situation where you need to be compatible with different versions of jars. Whether it is the maven solution or modifying the jar yourself, etc., you can circumvent the parent delegation mechanism of jvm. The higher the level of the class loader, the earlier it will load the files in its loading path. kind. Such as maven’s shortest dependency path, modifying the package name yourself, etc.
So when the above is both necessary and necessary, it is undoubtedly a better solution to replace the package name and import according to version. You only need to execute the command line to create a new set of jars. jarjar.jar is undoubtedly the first choice

Finally, I wish you all a happy time! ! !