From 60b1fe95805727e7e28e8073b0e4f4100d88e31b Mon Sep 17 00:00:00 2001 From: Kamil Krzywanski Date: Tue, 4 Nov 2025 23:05:36 +0100 Subject: [PATCH] Another fix for tests --- .../hotswap/agent/annotation/TestOnly.java | 40 +++++++++++++++++++ .../mybatis/proxy/ConfigurationProxy.java | 20 ++++++---- .../SpringMybatisConfigurationProxy.java | 14 +++++-- .../agent/plugin/mybatis/BaseTest.java | 2 +- ...PluginTest.java => MyBatisPluginTest.java} | 4 +- .../plugin/mybatis/MybatisSpringBootTest.java | 2 + .../plugin/mybatis/MybatisSpringTest.java | 2 + .../plugin/mybatis/proxy/ProxyReset.java | 11 +++++ 8 files changed, 82 insertions(+), 13 deletions(-) create mode 100644 hotswap-agent-core/src/main/java/org/hotswap/agent/annotation/TestOnly.java rename plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/{AMyBatisPluginTest.java => MyBatisPluginTest.java} (95%) create mode 100644 plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/proxy/ProxyReset.java diff --git a/hotswap-agent-core/src/main/java/org/hotswap/agent/annotation/TestOnly.java b/hotswap-agent-core/src/main/java/org/hotswap/agent/annotation/TestOnly.java new file mode 100644 index 000000000..b2f2e569f --- /dev/null +++ b/hotswap-agent-core/src/main/java/org/hotswap/agent/annotation/TestOnly.java @@ -0,0 +1,40 @@ +package org.hotswap.agent.annotation; + +import java.lang.annotation.*; + +/** + * Indicates that the visibility of a field, method, or constructor + * has been relaxed to make the code testable. + *

+ * This annotation serves purely as documentation — it does not change + * visibility or behavior at runtime. It helps other developers understand + * that a particular element is exposed for testing purposes and should not + * be used by production code directly. + *

+ * + *

Typical usage:

+ *
{@code
+ * class MyService {
+ *
+ *     @VisibleForTesting
+ *     void computeInternalLogic() {
+ *         // Exposed only for test visibility
+ *     }
+ * }
+ * }
+ * + *

Best practice:

+ * Keep such methods package-private and place test classes + * in the same package so that tests can access them. + */ +@Documented +@Retention(RetentionPolicy.SOURCE) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE}) +public @interface TestOnly { + /** + * Optional note describing why this element is visible for testing. + * + * @return explanation or context for the increased visibility + */ + String value() default ""; +} diff --git a/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/ConfigurationProxy.java b/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/ConfigurationProxy.java index 2ca13de79..cf839baaf 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/ConfigurationProxy.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/ConfigurationProxy.java @@ -25,6 +25,7 @@ import org.apache.ibatis.builder.xml.XMLConfigBuilder; import org.apache.ibatis.session.Configuration; +import org.hotswap.agent.annotation.TestOnly; import org.hotswap.agent.javassist.util.proxy.MethodHandler; import org.hotswap.agent.javassist.util.proxy.ProxyFactory; import org.hotswap.agent.logging.AgentLogger; @@ -41,7 +42,7 @@ public class ConfigurationProxy { private static AgentLogger LOGGER = AgentLogger.getLogger(ConfigurationProxy.class); - private static Map proxiedConfigurations = new HashMap<>(); + private static final Map proxiedConfigurations = new HashMap<>(); public static ConfigurationProxy getWrapper(XMLConfigBuilder configBuilder) { /* @@ -53,10 +54,10 @@ public static ConfigurationProxy getWrapper(XMLConfigBuilder configBuilder) { return new ConfigurationProxy(configBuilder); } - if (!proxiedConfigurations.containsKey(configBuilder)) { - proxiedConfigurations.put(configBuilder, new ConfigurationProxy(configBuilder)); - } - return proxiedConfigurations.get(configBuilder); + return proxiedConfigurations.computeIfAbsent( + configBuilder, + ConfigurationProxy::new + ); } public static void refreshProxiedConfigurations() { @@ -77,7 +78,7 @@ public void refreshProxiedConfiguration() throws NoSuchMethodException, Invocati ReflectionHelper.invoke(configBuilder, MyBatisTransformers.REFRESH_METHOD); } - private XMLConfigBuilder configBuilder; + private final XMLConfigBuilder configBuilder; private Configuration configuration; private Configuration proxyInstance; @@ -113,4 +114,9 @@ public static boolean isMybatisEntity(Class clazz) { return false; } -} \ No newline at end of file + + @TestOnly + protected static void reset() { + proxiedConfigurations.clear(); + } +} diff --git a/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/SpringMybatisConfigurationProxy.java b/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/SpringMybatisConfigurationProxy.java index 33c72f5f1..5236de336 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/SpringMybatisConfigurationProxy.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/main/java/org/hotswap/agent/plugin/mybatis/proxy/SpringMybatisConfigurationProxy.java @@ -1,6 +1,7 @@ package org.hotswap.agent.plugin.mybatis.proxy; import org.apache.ibatis.session.Configuration; +import org.hotswap.agent.annotation.TestOnly; import org.hotswap.agent.plugin.mybatis.transformers.ConfigurationCaller; import org.hotswap.agent.util.ReflectionHelper; @@ -16,10 +17,10 @@ public SpringMybatisConfigurationProxy(Object sqlSessionFactoryBean) { } public static SpringMybatisConfigurationProxy getWrapper(Object sqlSessionFactoryBean) { - if (!proxiedConfigurations.containsKey(sqlSessionFactoryBean)) { - proxiedConfigurations.put(sqlSessionFactoryBean, new SpringMybatisConfigurationProxy(sqlSessionFactoryBean)); - } - return proxiedConfigurations.get(sqlSessionFactoryBean); + return proxiedConfigurations.computeIfAbsent( + sqlSessionFactoryBean, + SpringMybatisConfigurationProxy::new + ); } public static boolean runningBySpringMybatis() { @@ -60,4 +61,9 @@ public static boolean isMybatisEntity(Class clazz) { return false; } + + @TestOnly + protected static void reset() { + proxiedConfigurations.clear(); + } } diff --git a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/BaseTest.java b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/BaseTest.java index e675cd2aa..e7ba12ddd 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/BaseTest.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/BaseTest.java @@ -50,7 +50,7 @@ protected static void swapMapper(String mapperNew, String dstMapperName) throws public boolean result() throws Exception { return !MyBatisRefreshCommands.reloadFlag; } - }, 4000 )); // Repository is regenerated within 2*DeltaSpikePlugin.WAIT_ON_REDEFINE + }, 7000 )); // Repository is regenerated within 2*DeltaSpikePlugin.WAIT_ON_REDEFINE // TODO do not know why sleep is needed, maybe a separate thread in owb refresh? Thread.sleep(100); diff --git a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/AMyBatisPluginTest.java b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MyBatisPluginTest.java similarity index 95% rename from plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/AMyBatisPluginTest.java rename to plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MyBatisPluginTest.java index 3f2965326..3fcfa3fd1 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/AMyBatisPluginTest.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MyBatisPluginTest.java @@ -22,6 +22,7 @@ import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; +import org.hotswap.agent.plugin.mybatis.proxy.ProxyReset; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -32,7 +33,7 @@ import static org.junit.Assert.assertEquals; -public class AMyBatisPluginTest extends BaseTest { +public class MyBatisPluginTest extends BaseTest { private static SqlSessionFactory sqlSessionFactory; @@ -52,6 +53,7 @@ public static void setup() throws Exception { @AfterClass public static void tearDown() throws Exception { + ProxyReset.reset(); File tmp = Resources.getResourceAsFile("org/hotswap/agent/plugin/mybatis/Mapper.xml"); tmp.delete(); } diff --git a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringBootTest.java b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringBootTest.java index 51c6f77bb..78329e047 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringBootTest.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringBootTest.java @@ -2,6 +2,7 @@ import org.apache.ibatis.io.Resources; import org.hotswap.agent.logging.AgentLogger; +import org.hotswap.agent.plugin.mybatis.proxy.ProxyReset; import org.hotswap.agent.plugin.mybatis.springboot.*; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -40,6 +41,7 @@ public static void setup() throws Exception { @AfterClass public static void tearDown() throws Exception { + ProxyReset.reset(); File f = Resources.getResourceAsFile("swapXML/BootUserMapper1.xml"); Files.copy(f.toPath(), f.toPath().getParent().resolve("BootUserMapper.xml"), StandardCopyOption.REPLACE_EXISTING); } diff --git a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringTest.java b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringTest.java index d3567dff7..6fa282c78 100644 --- a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringTest.java +++ b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/MybatisSpringTest.java @@ -1,6 +1,7 @@ package org.hotswap.agent.plugin.mybatis; import org.apache.ibatis.io.Resources; +import org.hotswap.agent.plugin.mybatis.proxy.ProxyReset; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -38,6 +39,7 @@ public static void setup() throws Exception { @AfterClass public static void tearDown() throws Exception { + ProxyReset.reset(); File tmp = Resources.getResourceAsFile("org/hotswap/agent/plugin/mybatis/Mapper.xml"); tmp.delete(); } diff --git a/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/proxy/ProxyReset.java b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/proxy/ProxyReset.java new file mode 100644 index 000000000..a065ae6b4 --- /dev/null +++ b/plugin/hotswap-agent-mybatis-plugin/src/test/java/org/hotswap/agent/plugin/mybatis/proxy/ProxyReset.java @@ -0,0 +1,11 @@ +package org.hotswap.agent.plugin.mybatis.proxy; + +/** + * Utility method to access reset methods for Proxy Configurations + */ +public class ProxyReset { + public static void reset() { + ConfigurationProxy.reset(); + SpringMybatisConfigurationProxy.reset(); + } +}