-
Notifications
You must be signed in to change notification settings - Fork 35
Description
I have a mapper which passes prepared parameters into velocity macro. And this fails for at least two cases:
- When parameters in macro are used in different order than they are defined in the macro;
- When parameters are used more than one time in macro.
Most probably is is due to the changes in velocity from version 2.0 where they changed when arguments are evaluated (https://velocity.apache.org/engine/2.4.1/upgrading.html#vtl-changes_3):
Velocimacro arguments are now evaluated only once (instead of each time they were referenced inside the macro body as was the case for v1.7) and passed by value (or more precisely as reference after evaluation).
Using parameters in other order than they are defined
Mapper:
<select id="selectFromMacroParamsOrder" resultType="org.mybatis.scripting.velocity.use.Name">
#macro(select_values $firstName, $lastName)
SELECT firstName, lastName FROM (VALUES ($lastName, $firstName)) as tmp (lastName, firstName)
#end
#select_values(@{firstName}, @{lastName})
</select>Test:
@Test
public void testSelectFromMacroWithParametersOrdering() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
Name fred = new Name();
fred.setFirstName("Fred");
fred.setLastName("Flinstone");
List<Name> answers = sqlSession.selectList("org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder", fred);
assertEquals(1, answers.size());
assertEquals(answers.get(0).getFirstName(), fred.getFirstName());
assertEquals(answers.get(0).getLastName(), fred.getLastName());
}
}MyBatis mapper logs:
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - ==> Preparing: SELECT firstName, lastName FROM (VALUES (?, ?)) as tmp (lastName, firstName)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - ==> Parameters: Fred(String), Flinstone(String)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - <== Total: 1
Using parameters more than once in macro
Mapper:
<select id="selectFromMacroMultipleTimes" resultType="java.lang.String">
#macro(select_multiple $value)
SELECT * FROM (VALUES ($value), ($value)) as tmp (v)
#end
#select_multiple(@{value})
</select>Test:
@Test
public void testSelectFromMacroMultipleTimes() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
List<String> answers = sqlSession.selectList("org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes", "A");
assertEquals(2, answers.size());
assertEquals(answers.get(0), "A");
assertEquals(answers.get(1), "A");
}
}MyBatis mapper logs:
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes - ==> Preparing: SELECT * FROM (VALUES (?), (?)) as tmp (v)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes - ==> Parameters: A(String)
Probably the ParameterMappingCollector should return some 'proxy' from org.mybatis.scripting.velocity.ParameterMappingCollector.g(int) method, which would add parameter mapping on toString call.