From ff03cc3565d67a86eeec9b1fc7f180b57865bf76 Mon Sep 17 00:00:00 2001 From: Mark Pollack Date: Tue, 19 Aug 2025 00:20:26 -0400 Subject: [PATCH] Fix IllegalAccessException in MongoDbAtlasLocalContainerConnectionDetails.getSslBundle() The original fix in commit 03d475e introduced a MethodHandles.unreflectSpecial() approach to resolve a StackOverflowError, but this caused IllegalAccessException due to incorrect usage of unreflectSpecial() for interface default methods. The unreflectSpecial() method is designed for superclass method calls, not interface default methods, and requires private access which caused: "IllegalAccessException: no private access for invokespecial: interface org.springframework.boot.autoconfigure.mongo.MongoConnectionDetails" This fix replaces the complex reflection approach with simple interface delegation using 'MongoConnectionDetails.super.getSslBundle()'. This solution: - Eliminates IllegalAccessException by properly overriding with public access - Avoids StackOverflowError by delegating to interface default method - Removes all reflection code, making it simpler and more maintainable - Works across all Spring Boot versions without version-specific checks - Resolves access privilege conflict between interface and parent class The interface default method returns null, which is the desired behavior for SSL configuration when no custom SSL bundle is provided. Fixes: https://github.com/spring-projects/spring-ai/actions/runs/16981113833 Signed-off-by: Mark Pollack --- ...ocalContainerConnectionDetailsFactory.java | 27 +++---------------- 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java index 32bd405326e..d650346dd88 100644 --- a/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java +++ b/spring-ai-spring-boot-testcontainers/src/main/java/org/springframework/ai/testcontainers/service/connection/mongo/MongoDbAtlasLocalContainerConnectionDetailsFactory.java @@ -16,9 +16,6 @@ package org.springframework.ai.testcontainers.service.connection.mongo; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Method; - import com.mongodb.ConnectionString; import org.testcontainers.mongodb.MongoDBAtlasLocalContainer; @@ -26,7 +23,6 @@ import org.springframework.boot.ssl.SslBundle; import org.springframework.boot.testcontainers.service.connection.ContainerConnectionDetailsFactory; import org.springframework.boot.testcontainers.service.connection.ContainerConnectionSource; -import org.springframework.util.ReflectionUtils; /** * A {@link ContainerConnectionDetailsFactory} implementation that provides @@ -51,12 +47,6 @@ class MongoDbAtlasLocalContainerConnectionDetailsFactory extends ContainerConnectionDetailsFactory { - private static final Method GET_SSL_BUNDLE_METHOD; - - static { - GET_SSL_BUNDLE_METHOD = ReflectionUtils.findMethod(MongoConnectionDetails.class, "getSslBundle"); - } - @Override protected MongoConnectionDetails getContainerConnectionDetails( ContainerConnectionSource source) { @@ -79,21 +69,10 @@ public ConnectionString getConnectionString() { return new ConnectionString(getContainer().getConnectionString()); } - // Conditional implementation based on whether the method exists + @Override public SslBundle getSslBundle() { - if (GET_SSL_BUNDLE_METHOD != null) { // Boot 3.5.x+ - try { - return (SslBundle) MethodHandles.lookup() - .in(GET_SSL_BUNDLE_METHOD.getDeclaringClass()) - .unreflectSpecial(GET_SSL_BUNDLE_METHOD, GET_SSL_BUNDLE_METHOD.getDeclaringClass()) - .bindTo(this) - .invokeWithArguments(); - } - catch (Throwable e) { - throw new RuntimeException(e); - } - } - return null; // Boot 3.4.x (No-Op) + // Delegate to the interface default method by calling it explicitly + return MongoConnectionDetails.super.getSslBundle(); } }