From 0b4a7f0531d32fc824041501672e80942672cbf7 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sat, 31 Dec 2022 14:21:32 +0900 Subject: [PATCH 1/5] Remove DynamicContext reference It's used as a Map. --- .../thymeleaf/ThymeleafSqlSource.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java index 3d26f4ea..bf5a6155 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java @@ -18,6 +18,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; @@ -90,16 +91,19 @@ public BoundSql getBoundSql(Object parameterObject) { processingParameterType = parameterType; } - DynamicContext dynamicContext = new DynamicContext(configuration, parameterObject); - Map customVariables = dynamicContext.getBindings(); + Map bindings = new HashMap<>(); + bindings.put(DynamicContext.PARAMETER_OBJECT_KEY, parameterObject); + bindings.put(DynamicContext.DATABASE_ID_KEY, configuration.getDatabaseId()); + + Map customVariables = bindings; customVariables.put(TemporaryTakeoverKeys.CONFIGURATION, configuration); - customVariables.put(TemporaryTakeoverKeys.DYNAMIC_CONTEXT, dynamicContext); + customVariables.put(TemporaryTakeoverKeys.DYNAMIC_CONTEXT, bindings); customVariables.put(TemporaryTakeoverKeys.PROCESSING_PARAMETER_TYPE, processingParameterType); - String sql = sqlGenerator.generate(sqlTemplate, parameterObject, dynamicContext::bind, customVariables); + String sql = sqlGenerator.generate(sqlTemplate, parameterObject, bindings::put, customVariables); - SqlSource sqlSource = sqlSourceBuilder.parse(sql, processingParameterType, dynamicContext.getBindings()); + SqlSource sqlSource = sqlSourceBuilder.parse(sql, processingParameterType, bindings); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); - dynamicContext.getBindings().forEach(boundSql::setAdditionalParameter); + bindings.forEach(boundSql::setAdditionalParameter); return boundSql; } @@ -116,20 +120,20 @@ static class ContextFactory implements BiFunction, I @Override public IContext apply(Object parameter, Map customVariable) { Configuration configuration = (Configuration) customVariable.remove(TemporaryTakeoverKeys.CONFIGURATION); - DynamicContext dynamicContext = (DynamicContext) customVariable.remove(TemporaryTakeoverKeys.DYNAMIC_CONTEXT); + Map bindings = (Map) customVariable.remove(TemporaryTakeoverKeys.DYNAMIC_CONTEXT); Class processingParameterType = (Class) customVariable .remove(TemporaryTakeoverKeys.PROCESSING_PARAMETER_TYPE); MyBatisBindingContext bindingContext = new MyBatisBindingContext( parameter != null && configuration.getTypeHandlerRegistry().hasTypeHandler(processingParameterType)); - dynamicContext.bind(MyBatisBindingContext.CONTEXT_VARIABLE_NAME, bindingContext); + bindings.put(MyBatisBindingContext.CONTEXT_VARIABLE_NAME, bindingContext); IContext context; if (parameter instanceof Map) { @SuppressWarnings(value = "unchecked") Map map = (Map) parameter; - context = new MapBasedContext(map, dynamicContext, configuration.getVariables()); + context = new MapBasedContext(map, bindings, configuration.getVariables()); } else { MetaClass metaClass = MetaClass.forClass(processingParameterType, configuration.getReflectorFactory()); - context = new MetaClassBasedContext(parameter, metaClass, processingParameterType, dynamicContext, + context = new MetaClassBasedContext(parameter, metaClass, processingParameterType, bindings, configuration.getVariables()); } return context; @@ -138,15 +142,15 @@ public IContext apply(Object parameter, Map customVariable) { private abstract static class AbstractContext implements IContext { - private final DynamicContext dynamicContext; + private final Map dynamicContext; private final Properties configurationProperties; private final Set variableNames; - private AbstractContext(DynamicContext dynamicContext, Properties configurationProperties) { + private AbstractContext(Map dynamicContext, Properties configurationProperties) { this.dynamicContext = dynamicContext; this.configurationProperties = configurationProperties; this.variableNames = new HashSet<>(); - addVariableNames(dynamicContext.getBindings().keySet()); + addVariableNames(dynamicContext.keySet()); Optional.ofNullable(configurationProperties).ifPresent(v -> addVariableNames(v.stringPropertyNames())); } @@ -183,8 +187,8 @@ public Set getVariableNames() { */ @Override public Object getVariable(String name) { - if (dynamicContext.getBindings().containsKey(name)) { - return dynamicContext.getBindings().get(name); + if (dynamicContext.containsKey(name)) { + return dynamicContext.get(name); } if (configurationProperties != null && configurationProperties.containsKey(name)) { return configurationProperties.getProperty(name); @@ -200,7 +204,7 @@ private static class MapBasedContext extends AbstractContext { private final Map variables; - private MapBasedContext(Map parameterMap, DynamicContext dynamicContext, + private MapBasedContext(Map parameterMap, Map dynamicContext, Properties configurationProperties) { super(dynamicContext, configurationProperties); this.variables = parameterMap; @@ -224,7 +228,7 @@ private static class MetaClassBasedContext extends AbstractContext { private final Class parameterType; private MetaClassBasedContext(Object parameterObject, MetaClass parameterMetaClass, Class parameterType, - DynamicContext dynamicContext, Properties configurationProperties) { + Map dynamicContext, Properties configurationProperties) { super(dynamicContext, configurationProperties); this.parameterObject = parameterObject; this.parameterMetaClass = parameterMetaClass; From 21f590746b9ef49caeec88bf577b2075004c40af Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sat, 31 Dec 2022 14:31:51 +0900 Subject: [PATCH 2/5] Adjustment for https://github.com/mybatis/mybatis-3/pull/2760 --- .../thymeleaf/ThymeleafSqlSource.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java index bf5a6155..178073b5 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 the original author or authors. + * Copyright 2018-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,12 @@ package org.mybatis.scripting.thymeleaf; import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Optional; @@ -27,9 +29,12 @@ import java.util.Set; import java.util.function.BiFunction; +import org.apache.ibatis.builder.ParameterMappingTokenHandler; import org.apache.ibatis.builder.SqlSourceBuilder; import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.ParameterMapping; import org.apache.ibatis.mapping.SqlSource; +import org.apache.ibatis.parsing.GenericTokenParser; import org.apache.ibatis.reflection.MetaClass; import org.apache.ibatis.scripting.xmltags.DynamicContext; import org.apache.ibatis.session.Configuration; @@ -54,7 +59,6 @@ private static class TemporaryTakeoverKeys { private final Configuration configuration; private final SqlGenerator sqlGenerator; - private final SqlSourceBuilder sqlSourceBuilder; private final String sqlTemplate; private final Class parameterType; @@ -76,7 +80,6 @@ private static class TemporaryTakeoverKeys { this.sqlGenerator = sqlGenerator; this.sqlTemplate = sqlTemplate; this.parameterType = parameterType; - this.sqlSourceBuilder = new SqlSourceBuilder(configuration); } /** @@ -101,13 +104,23 @@ public BoundSql getBoundSql(Object parameterObject) { customVariables.put(TemporaryTakeoverKeys.PROCESSING_PARAMETER_TYPE, processingParameterType); String sql = sqlGenerator.generate(sqlTemplate, parameterObject, bindings::put, customVariables); - SqlSource sqlSource = sqlSourceBuilder.parse(sql, processingParameterType, bindings); + SqlSource sqlSource = parse(configuration, sql, parameterObject, bindings); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); bindings.forEach(boundSql::setAdditionalParameter); return boundSql; } + private static SqlSource parse(Configuration configuration, String originalSql, Object parameterObject, + Map additionalParameters) { + Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); + List parameterMappings = new ArrayList<>(); + ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(parameterMappings, configuration, + parameterObject, parameterType, additionalParameters, true); + GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); + return SqlSourceBuilder.buildSqlSource(configuration, parser.parse(originalSql), parameterMappings); + } + /** * The factory class for Thymeleaf's context. * @@ -120,7 +133,7 @@ static class ContextFactory implements BiFunction, I @Override public IContext apply(Object parameter, Map customVariable) { Configuration configuration = (Configuration) customVariable.remove(TemporaryTakeoverKeys.CONFIGURATION); - Map bindings = (Map) customVariable.remove(TemporaryTakeoverKeys.DYNAMIC_CONTEXT); + Map bindings = (Map) customVariable.remove(TemporaryTakeoverKeys.DYNAMIC_CONTEXT); Class processingParameterType = (Class) customVariable .remove(TemporaryTakeoverKeys.PROCESSING_PARAMETER_TYPE); MyBatisBindingContext bindingContext = new MyBatisBindingContext( From aade0b2d039e751f4a401292d7d30e12670c7df7 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 15 Mar 2026 02:34:32 +0900 Subject: [PATCH 3/5] [pom] Bump mybatis.version to 3.6.0-SNAPSHOT --- pom.xml | 4 ++-- .../org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d0e8532d..e84b9f2f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ - 3.5.19 + 3.6.0-SNAPSHOT 3.1.3.RELEASE diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java index 178073b5..69cf25ca 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2025 the original author or authors. + * Copyright 2018-2026 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 5483faa563211f916bbf594d8a082659da740b90 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Sun, 15 Mar 2026 02:44:25 +0900 Subject: [PATCH 4/5] Include snapshot repository --- pom.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pom.xml b/pom.xml index e84b9f2f..a279bcf3 100644 --- a/pom.xml +++ b/pom.xml @@ -214,4 +214,12 @@ + + + sonatype-oss-snapshots + Sonatype OSS Snapshots Repository + https://central.sonatype.com/repository/maven-snapshots/ + + + From 1f2c18208b7c3a730c2f5b1923ec1fe41e38c305 Mon Sep 17 00:00:00 2001 From: Iwao AVE! Date: Mon, 16 Mar 2026 02:23:42 +0900 Subject: [PATCH 5/5] Adjustment to the recent core changes --- .../thymeleaf/ThymeleafLanguageDriver.java | 19 ++++++++++++++++--- .../thymeleaf/ThymeleafSqlSource.java | 19 ++++++++++++++++--- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafLanguageDriver.java b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafLanguageDriver.java index 38d1caa6..9ec40de7 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafLanguageDriver.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafLanguageDriver.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2022 the original author or authors. + * Copyright 2018-2026 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.parsing.XNode; +import org.apache.ibatis.reflection.ParamNameResolver; import org.apache.ibatis.scripting.LanguageDriver; import org.apache.ibatis.scripting.defaults.DefaultParameterHandler; import org.apache.ibatis.session.Configuration; @@ -84,7 +85,7 @@ public ParameterHandler createParameterHandler(MappedStatement mappedStatement, */ @Override public SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType) { - return createSqlSource(configuration, script.getNode().getTextContent(), parameterType); + return createSqlSource(configuration, script.getNode().getTextContent(), parameterType, null); } /** @@ -92,7 +93,19 @@ public SqlSource createSqlSource(Configuration configuration, XNode script, Clas */ @Override public SqlSource createSqlSource(Configuration configuration, String script, Class parameterType) { - return new ThymeleafSqlSource(configuration, sqlGenerator, script.trim(), parameterType); + return createSqlSource(configuration, script, parameterType, null); + } + + @Override + public SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType, + ParamNameResolver paramNameResolver) { + return createSqlSource(configuration, script.getNode().getTextContent(), parameterType, paramNameResolver); + } + + @Override + public SqlSource createSqlSource(Configuration configuration, String script, Class parameterType, + ParamNameResolver paramNameResolver) { + return new ThymeleafSqlSource(configuration, sqlGenerator, script.trim(), parameterType, paramNameResolver); } } diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java index 69cf25ca..4c24a03e 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/ThymeleafSqlSource.java @@ -36,6 +36,7 @@ import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.parsing.GenericTokenParser; import org.apache.ibatis.reflection.MetaClass; +import org.apache.ibatis.reflection.ParamNameResolver; import org.apache.ibatis.scripting.xmltags.DynamicContext; import org.apache.ibatis.session.Configuration; import org.thymeleaf.context.IContext; @@ -61,6 +62,7 @@ private static class TemporaryTakeoverKeys { private final SqlGenerator sqlGenerator; private final String sqlTemplate; private final Class parameterType; + private final ParamNameResolver paramNameResolver; /** * Constructor for for integrating with template engine provide by Thymeleaf. @@ -74,12 +76,23 @@ private static class TemporaryTakeoverKeys { * @param parameterType * A parameter type that specified at mapper method argument or xml element */ + ThymeleafSqlSource(Configuration configuration, SqlGenerator sqlGenerator, String sqlTemplate, Class parameterType, + ParamNameResolver paramNameResolver) { + this.configuration = configuration; + this.sqlGenerator = sqlGenerator; + this.sqlTemplate = sqlTemplate; + this.parameterType = parameterType; + this.paramNameResolver = paramNameResolver; + } + + @Deprecated ThymeleafSqlSource(Configuration configuration, SqlGenerator sqlGenerator, String sqlTemplate, Class parameterType) { this.configuration = configuration; this.sqlGenerator = sqlGenerator; this.sqlTemplate = sqlTemplate; this.parameterType = parameterType; + this.paramNameResolver = null; } /** @@ -104,7 +117,7 @@ public BoundSql getBoundSql(Object parameterObject) { customVariables.put(TemporaryTakeoverKeys.PROCESSING_PARAMETER_TYPE, processingParameterType); String sql = sqlGenerator.generate(sqlTemplate, parameterObject, bindings::put, customVariables); - SqlSource sqlSource = parse(configuration, sql, parameterObject, bindings); + SqlSource sqlSource = parse(configuration, sql, parameterObject, bindings, paramNameResolver); BoundSql boundSql = sqlSource.getBoundSql(parameterObject); bindings.forEach(boundSql::setAdditionalParameter); @@ -112,11 +125,11 @@ public BoundSql getBoundSql(Object parameterObject) { } private static SqlSource parse(Configuration configuration, String originalSql, Object parameterObject, - Map additionalParameters) { + Map additionalParameters, ParamNameResolver pnResolver) { Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); List parameterMappings = new ArrayList<>(); ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(parameterMappings, configuration, - parameterObject, parameterType, additionalParameters, true); + parameterObject, parameterType, additionalParameters, pnResolver, false); GenericTokenParser parser = new GenericTokenParser("#{", "}", handler); return SqlSourceBuilder.buildSqlSource(configuration, parser.parse(originalSql), parameterMappings); }