diff --git a/core/src/main/java/tk/mybatis/mapper/util/OGNL.java b/core/src/main/java/tk/mybatis/mapper/util/OGNL.java index 81017e575..39e88fb37 100644 --- a/core/src/main/java/tk/mybatis/mapper/util/OGNL.java +++ b/core/src/main/java/tk/mybatis/mapper/util/OGNL.java @@ -105,24 +105,39 @@ public static boolean notEmptyCollectionCheck(Object parameter, String error) { } /** - * 检查 parameter 对象中指定的 fields 是否全是 null,如果是则抛出异常 + * 检查 Example 中是否至少有一个有效的查询条件 + * 用于 safeDelete 和 safeUpdate 的安全检查,确保不会执行全表操作 * - * @param parameter - * @return + * @param parameter Example 对象或包含 getOredCriteria 方法的对象 + * @return 如果至少有一个有效的查询条件则返回 true + * @throws MapperException 如果参数为 null 或没有有效的查询条件 */ + @SuppressWarnings("unchecked") public static boolean exampleHasAtLeastOneCriteriaCheck(Object parameter) { if (parameter != null) { try { if (parameter instanceof Example) { List criteriaList = ((Example) parameter).getOredCriteria(); if (criteriaList != null && criteriaList.size() > 0) { - return true; + for (Example.Criteria criteria : criteriaList) { + if (criteria.isValid()) { + return true; + } + } } } else { Method getter = parameter.getClass().getDeclaredMethod("getOredCriteria"); Object list = getter.invoke(parameter); if (list != null && list instanceof List && ((List) list).size() > 0) { - return true; + Method isValidGetter = null; + for (Object criteria : (List) list) { + if (isValidGetter == null) { + isValidGetter = criteria.getClass().getDeclaredMethod("isValid"); + } + if ((Boolean) isValidGetter.invoke(criteria)) { + return true; + } + } } } } catch (Exception e) { diff --git a/core/src/test/java/tk/mybatis/mapper/test/util/TestOGNLCriteriaCheck.java b/core/src/test/java/tk/mybatis/mapper/test/util/TestOGNLCriteriaCheck.java new file mode 100644 index 000000000..ac56c9c80 --- /dev/null +++ b/core/src/test/java/tk/mybatis/mapper/test/util/TestOGNLCriteriaCheck.java @@ -0,0 +1,111 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 abel533@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package tk.mybatis.mapper.test.util; + +import org.junit.Test; +import tk.mybatis.mapper.MapperException; +import tk.mybatis.mapper.entity.Example; +import tk.mybatis.mapper.util.OGNL; + +import jakarta.persistence.Table; + +/** + * Test OGNL.exampleHasAtLeastOneCriteriaCheck method + * @author liuzh + */ +public class TestOGNLCriteriaCheck { + + // Simple test entity class with table annotation + @Table(name = "test_entity") + static class TestEntity { + private Integer id; + private String name; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + /** + * Test with null example - should throw MapperException + */ + @Test(expected = MapperException.class) + public void testNullExample() { + OGNL.exampleHasAtLeastOneCriteriaCheck(null); + } + + /** + * Test with empty criteria list - should throw MapperException + */ + @Test(expected = MapperException.class) + public void testEmptyCriteriaList() { + Example example = new Example(TestEntity.class); + OGNL.exampleHasAtLeastOneCriteriaCheck(example); + } + + /** + * Test with criteria that has no conditions (invalid) - should throw MapperException + */ + @Test(expected = MapperException.class) + public void testInvalidCriteria() { + Example example = new Example(TestEntity.class); + example.createCriteria(); // Create criteria but don't add any conditions + OGNL.exampleHasAtLeastOneCriteriaCheck(example); + } + + /** + * Test with criteria that has null value (invalid) - should throw MapperException + */ + @Test(expected = MapperException.class) + public void testCriteriaWithNullValue() { + Example example = new Example(TestEntity.class); + // When notNull=false (default), null values are ignored and no criteria is added + example.createCriteria().andEqualTo("name", null); + OGNL.exampleHasAtLeastOneCriteriaCheck(example); + } + + /** + * Test with multiple criteria where all are invalid - should throw MapperException + */ + @Test(expected = MapperException.class) + public void testMultipleInvalidCriteria() { + Example example = new Example(TestEntity.class); + example.createCriteria().andEqualTo("name", null); + example.or().andEqualTo("name", null); + OGNL.exampleHasAtLeastOneCriteriaCheck(example); + } +}