Skip to content

Commit

Permalink
Merge pull request #1487 from kazuki43zoo/gh-1486_allow-any-variable-…
Browse files Browse the repository at this point in the history
…name-on-ognl

Allow any variable name on ognl expression when specify single value object as parameter object
  • Loading branch information
kazuki43zoo committed Jun 14, 2019
2 parents ab0395c + f47b023 commit 08bcdb8
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 11 deletions.
Expand Up @@ -45,9 +45,10 @@ public class DynamicContext {
public DynamicContext(Configuration configuration, Object parameterObject) {
if (parameterObject != null && !(parameterObject instanceof Map)) {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
bindings = new ContextMap(metaObject);
boolean existsTypeHandler = configuration.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass());
bindings = new ContextMap(metaObject, existsTypeHandler);
} else {
bindings = new ContextMap(null);
bindings = new ContextMap(null, false);
}
bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
Expand Down Expand Up @@ -75,11 +76,12 @@ public int getUniqueNumber() {

static class ContextMap extends HashMap<String, Object> {
private static final long serialVersionUID = 2977601501966151582L;
private final MetaObject parameterMetaObject;
private final boolean fallbackParameterObject;

private MetaObject parameterMetaObject;

public ContextMap(MetaObject parameterMetaObject) {
public ContextMap(MetaObject parameterMetaObject, boolean fallbackParameterObject) {
this.parameterMetaObject = parameterMetaObject;
this.fallbackParameterObject = fallbackParameterObject;
}

@Override
Expand All @@ -89,12 +91,16 @@ public Object get(Object key) {
return super.get(strKey);
}

if (parameterMetaObject != null) {
if (parameterMetaObject == null) {
return null;
}

if (fallbackParameterObject && !parameterMetaObject.hasGetter(strKey)) {
return parameterMetaObject.getOriginalObject();
} else {
// issue #61 do not modify the context when reading
return parameterMetaObject.getValue(strKey);
}

return null;
}
}

Expand Down
@@ -1,5 +1,5 @@
/**
* Copyright 2009-2015 the original author or authors.
* Copyright 2009-2019 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.
Expand All @@ -17,6 +17,26 @@

import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface DynSqlMapper {
String selectDescription(@Param("p") String p);

List<String> selectDescriptionById(Integer id);
List<String> selectDescriptionByConditions(Conditions conditions);
List<String> selectDescriptionByConditions2(Conditions conditions);
List<String> selectDescriptionByConditions3(Conditions conditions);

class Conditions {
private Integer id;

public void setId(Integer id) {
this.id = id;
}

public Integer getId() {
return id;
}
}

}
35 changes: 33 additions & 2 deletions src/test/java/org/apache/ibatis/submitted/dynsql/DynSqlMapper.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2009-2015 the original author or authors.
Copyright 2009-2019 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.
Expand All @@ -16,7 +16,6 @@
limitations under the License.
-->

<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
Expand All @@ -30,4 +29,36 @@
WHERE id = 3
</if>
</select>
<select id="selectDescriptionById" resultType="string">
SELECT description
FROM ibtest.names
<if test="id != null">
WHERE id = #{id}
</if>
</select>
<!-- Specify a property name as variable name (Valid always) -->
<select id="selectDescriptionByConditions" resultType="string">
SELECT description
FROM ibtest.names
<if test="id != null">
WHERE id = #{id}
</if>
</select>
<!-- Specify a any name(object name) as variable name (Valid if exists type handler) -->
<select id="selectDescriptionByConditions2" resultType="string">
SELECT description
FROM ibtest.names
<if test="conditions != null">
WHERE id = #{conditions}
</if>
</select>
<!-- Specify a any name(object name) and nested property name (Valid if exists type handler) -->
<select id="selectDescriptionByConditions3" resultType="string">
SELECT description
FROM ibtest.names
<if test="conditions != null and conditions.id != null">
WHERE id = #{conditions.id}
</if>
</select>

</mapper>
133 changes: 133 additions & 0 deletions src/test/java/org/apache/ibatis/submitted/dynsql/DynSqlTest.java
Expand Up @@ -18,16 +18,24 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.ibatis.BaseDataTest;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeHandler;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.Reader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -133,4 +141,129 @@ void testBindNull() {
}
}

/**
* Verify that can specify any variable name for parameter object when parameter is value object that a type handler exists.
*
* https://github.com/mybatis/mybatis-3/issues/1486
*/
@Test
void testValueObjectWithoutParamAnnotation() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
List<String> descriptions = mapper.selectDescriptionById(3);
assertEquals(1, descriptions.size());
assertEquals("Pebbles", descriptions.get(0));

assertEquals(7, mapper.selectDescriptionById(null).size());
}
}

/**
* Variations for with https://github.com/mybatis/mybatis-3/issues/1486
*/
@Test
void testNonValueObjectWithoutParamAnnotation() {
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
List<String> descriptions = mapper.selectDescriptionByConditions(conditions);
assertEquals(1, descriptions.size());
assertEquals("Pebbles", descriptions.get(0));

assertEquals(7, mapper.selectDescriptionByConditions(null).size());
assertEquals(7, mapper.selectDescriptionByConditions(new DynSqlMapper.Conditions()).size());
}
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
try {
mapper.selectDescriptionByConditions2(conditions);
} catch (PersistenceException e) {
assertEquals("There is no getter for property named 'conditions' in 'class org.apache.ibatis.submitted.dynsql.DynSqlMapper$Conditions'", e.getCause().getMessage());
}
assertEquals(7, mapper.selectDescriptionByConditions2(null).size());
}
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
try {
mapper.selectDescriptionByConditions3(conditions);
} catch (PersistenceException e) {
assertEquals("There is no getter for property named 'conditions' in 'class org.apache.ibatis.submitted.dynsql.DynSqlMapper$Conditions'", e.getCause().getMessage());
}
assertEquals(7, mapper.selectDescriptionByConditions3(null).size());
}

}

/**
* Variations for with https://github.com/mybatis/mybatis-3/issues/1486
*/
@Test
void testCustomValueObjectWithoutParamAnnotation() throws IOException {
SqlSessionFactory sqlSessionFactory;
try (Reader configReader = Resources.getResourceAsReader("org/apache/ibatis/submitted/dynsql/MapperConfig.xml")) {
sqlSessionFactory = new SqlSessionFactoryBuilder().build(configReader);
// register type handler for the user defined class (= value object)
sqlSessionFactory.getConfiguration().getTypeHandlerRegistry().register(DynSqlMapper.Conditions.class, new TypeHandler<DynSqlMapper.Conditions>() {
@Override
public void setParameter(PreparedStatement ps, int i, DynSqlMapper.Conditions parameter, JdbcType jdbcType) throws SQLException {
if (parameter.getId() != null) {
ps.setInt(i, parameter.getId());
} else {
ps.setNull(i, JdbcType.INTEGER.TYPE_CODE);
}
}
@Override
public DynSqlMapper.Conditions getResult(ResultSet rs, String columnName) throws SQLException {
return null;
}
@Override
public DynSqlMapper.Conditions getResult(ResultSet rs, int columnIndex) throws SQLException {
return null;
}
@Override
public DynSqlMapper.Conditions getResult(CallableStatement cs, int columnIndex) throws SQLException {
return null;
}
});
}
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
List<String> descriptions = mapper.selectDescriptionByConditions(conditions);
assertEquals(1, descriptions.size());
assertEquals("Pebbles", descriptions.get(0));

assertEquals(7, mapper.selectDescriptionByConditions(null).size());
assertEquals(7, mapper.selectDescriptionByConditions(new DynSqlMapper.Conditions()).size());
}
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
List<String> descriptions = mapper.selectDescriptionByConditions2(conditions);
assertEquals(1, descriptions.size());
assertEquals("Pebbles", descriptions.get(0));

assertEquals(7, mapper.selectDescriptionByConditions2(null).size());
assertEquals(0, mapper.selectDescriptionByConditions2(new DynSqlMapper.Conditions()).size());
}
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
DynSqlMapper mapper = sqlSession.getMapper(DynSqlMapper.class);
DynSqlMapper.Conditions conditions = new DynSqlMapper.Conditions();
conditions.setId(3);
List<String> descriptions = mapper.selectDescriptionByConditions3(conditions);
assertEquals(1, descriptions.size());
assertEquals("Pebbles", descriptions.get(0));

assertEquals(7, mapper.selectDescriptionByConditions3(null).size());
assertEquals(7, mapper.selectDescriptionByConditions3(new DynSqlMapper.Conditions()).size());
}
}

}

0 comments on commit 08bcdb8

Please sign in to comment.