Recently I had the need to change certain classes -from external dependencies- loaded on a Spring Boot application. All this happened in a very restrictive environment, where I was not allowed to use other libraries or tweak the JRE, it was only possible to modify the and environment variables or system properties. fat JAR I managed to change the dependency behaviour taking advantage of the way the works. In my case, because the class was part of a dependency and not the JRE, I decided to just rely on the App Class Loader. Of course, this is not Spring specific, this is more "any JVM app" specific :-) Java Class Loading System NOTE: For cases where the classes are part of the JRE, you could use the “ ” option (Java < 9) or for recent versions. -Xbootclasspath/a:path Jigsaw The App Class Loader would pick any class available in your classpath before going to check your dependencies. For that reason, if you add a class with the same qualified name -that respects the original contract- you could “hack” the dependency behaviour. For demoing the technique, I chose the library and changed the with a custom implementation of the . Jasypt BasicTextEncryptor Caesar cipher algorithm The original BasicTextEncryptor used a PBEWithMD5AndDES algorithm and the “new” implementation looks like this: org.jasypt.util.text; { String password; { .password = password; } { .password = String(password); } { cipher(message, password.length()); } { cipher(encryptedMessage, - password.length()); } { StringBuffer result= StringBuffer(); ( i = ; i < message.length(); i++) { (Character.isUpperCase(message.charAt(i))) { ch = (( )message.charAt(i) + shift - ) % + ; result.append(( )ch); } { ch = (( )message.charAt(i) + shift - ) % + ; result.append(( )ch); } } result.toString(); } } package /** * Overrides the original implementation with a Caesar Cipher Algorithm implementation */ public final class BasicTextEncryptor implements TextEncryptor private public void setPassword ( String password) final this public void setPasswordCharArray ( [] password) final char this new @Override String public encrypt ( String message) final return @Override String public decrypt ( String encryptedMessage) final return 26 String private cipher (String message, shift) int new for int 0 if int int 65 26 65 char else int int 97 26 97 char return My tests prove the point, the application now uses my custom implementation: { BasicTextEncryptor textEncryptor; { textEncryptor = BasicTextEncryptor(); textEncryptor.setPasswordCharArray( .toCharArray()); } { ClassLoader actualClassLoader = textEncryptor.getClass().getClassLoader(); assertTrue(actualClassLoader.toString().contains( )); } { String actual = textEncryptor.encrypt( ); assertEquals( , actual); } { String actual = textEncryptor.decrypt( ); assertEquals( , actual); } } public class JasyptTest private @BeforeEach public void setUp () new "123" @Test public void hackJasyptBasicEncryptor_shouldUseAppClassLoader () "AppClassLoader" @Test public void hackJasyptBasicEncryptor_encrypt () "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "DEFGHIJKLMNOPQRSTUVWXYZABC" @Test public void hackJasyptBasicEncryptor_decrypt () "DEFGHIJKLMNOPQRSTUVWXYZABC" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" The AppClassLoader loads the custom BasicTextEncryptor and as you can see the encrypt/decrypt methods now use the Caesar algorithm. In a “normal” project you should not need to override the dependency or JRE classes behaviour, but in case you need to, I hope this technique would do the trick for you. After our project I kept thinking about all the different possibilities enabled by tweaking the class loading process... Certainly, something to consider and with special care when wearing the security hat.