diff --git a/src/main/java/org/apache/ibatis/binding/MapperMethod.java b/src/main/java/org/apache/ibatis/binding/MapperMethod.java index c822a4e3ec4..8fc13623b09 100644 --- a/src/main/java/org/apache/ibatis/binding/MapperMethod.java +++ b/src/main/java/org/apache/ibatis/binding/MapperMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -54,53 +54,65 @@ public MapperMethod(Class mapperInterface, Method method, Configuration confi this.method = new MethodSignature(config, mapperInterface, method); } + private boolean isInsertOrUpdateOrDelete(SqlCommandType type) { + return type == SqlCommandType.INSERT || type == SqlCommandType.UPDATE || type == SqlCommandType.DELETE; + } + public Object execute(SqlSession sqlSession, Object[] args) { Object result; - switch (command.getType()) { - case INSERT: { - Object param = method.convertArgsToSqlCommandParam(args); - result = rowCountResult(sqlSession.insert(command.getName(), param)); - break; - } - case UPDATE: { - Object param = method.convertArgsToSqlCommandParam(args); - result = rowCountResult(sqlSession.update(command.getName(), param)); - break; - } - case DELETE: { - Object param = method.convertArgsToSqlCommandParam(args); - result = rowCountResult(sqlSession.delete(command.getName(), param)); - break; - } - case SELECT: - if (method.returnsVoid() && method.hasResultHandler()) { - executeWithResultHandler(sqlSession, args); - result = null; - } else if (method.returnsMany()) { - result = executeForMany(sqlSession, args); - } else if (method.returnsMap()) { - result = executeForMap(sqlSession, args); - } else if (method.returnsCursor()) { - result = executeForCursor(sqlSession, args); - } else { - Object param = method.convertArgsToSqlCommandParam(args); - result = sqlSession.selectOne(command.getName(), param); - if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { - result = Optional.ofNullable(result); - } - } - break; - case FLUSH: - result = sqlSession.flushStatements(); - break; + SqlCommandType type = command.getType(); + if (isInsertOrUpdateOrDelete(type)) { + Object param = method.convertArgsToSqlCommandParam(args); + result = rowCountResult(executeSqlCommand(sqlSession, type, param)); + } else if (type == SqlCommandType.SELECT) { + result = executeSelect(sqlSession, args); + } else if (type == SqlCommandType.FLUSH) { + result = sqlSession.flushStatements(); + } else { + throw new BindingException("Unknown execution method for: " + command.getName()); + } + validateResult(result); + return result; + } + + private int executeSqlCommand(SqlSession sqlSession, SqlCommandType type, Object param) { + switch (type) { + case INSERT: + return sqlSession.insert(command.getName(), param); + case UPDATE: + return sqlSession.update(command.getName(), param); + case DELETE: + return sqlSession.delete(command.getName(), param); default: - throw new BindingException("Unknown execution method for: " + command.getName()); + throw new BindingException("Unsupported SqlCommandType: " + type); + } + } + + private Object executeSelect(SqlSession sqlSession, Object[] args) { + if (method.returnsVoid() && method.hasResultHandler()) { + executeWithResultHandler(sqlSession, args); + return null; + } else if (method.returnsMany()) { + return executeForMany(sqlSession, args); + } else if (method.returnsMap()) { + return executeForMap(sqlSession, args); + } else if (method.returnsCursor()) { + return executeForCursor(sqlSession, args); + } else { + Object param = method.convertArgsToSqlCommandParam(args); + Object result = sqlSession.selectOne(command.getName(), param); + if (method.returnsOptional() && (result == null || !method.getReturnType().equals(result.getClass()))) { + result = Optional.ofNullable(result); + } + return result; } + } + + private void validateResult(Object result) { if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) { throw new BindingException("Mapper method '" + command.getName() + "' attempted to return null from a method with a primitive return type (" + method.getReturnType() + ")."); } - return result; } private Object rowCountResult(int rowCount) { diff --git a/src/main/java/org/apache/ibatis/binding/MapperRegistry.java b/src/main/java/org/apache/ibatis/binding/MapperRegistry.java index a87cbb09102..d882611aeb8 100644 --- a/src/main/java/org/apache/ibatis/binding/MapperRegistry.java +++ b/src/main/java/org/apache/ibatis/binding/MapperRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -18,11 +18,9 @@ import java.util.Collection; import java.util.Collections; import java.util.Map; -import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder; -import org.apache.ibatis.io.ResolverUtil; import org.apache.ibatis.session.Configuration; import org.apache.ibatis.session.SqlSession; @@ -65,9 +63,6 @@ public void addMapper(Class type) { boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<>(type)); - // It's important that the type is added before the parser is run - // otherwise the binding may automatically be attempted by the - // mapper parser. If the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; @@ -79,46 +74,15 @@ public void addMapper(Class type) { } } - /** - * Gets the mappers. - * - * @return the mappers - * - * @since 3.2.2 - */ public Collection> getMappers() { return Collections.unmodifiableCollection(knownMappers.keySet()); } - /** - * Adds the mappers. - * - * @param packageName - * the package name - * @param superType - * the super type - * - * @since 3.2.2 - */ public void addMappers(String packageName, Class superType) { - ResolverUtil> resolverUtil = new ResolverUtil<>(); - resolverUtil.find(new ResolverUtil.IsA(superType), packageName); - Set>> mapperSet = resolverUtil.getClasses(); - for (Class mapperClass : mapperSet) { - addMapper(mapperClass); - } + MapperRegistryHelper.addMappers(this, packageName, superType); } - /** - * Adds the mappers. - * - * @param packageName - * the package name - * - * @since 3.2.2 - */ public void addMappers(String packageName) { - addMappers(packageName, Object.class); + MapperRegistryHelper.addMappers(this, packageName); } - } diff --git a/src/main/java/org/apache/ibatis/binding/MapperRegistryHelper.java b/src/main/java/org/apache/ibatis/binding/MapperRegistryHelper.java new file mode 100644 index 00000000000..5b2503c7873 --- /dev/null +++ b/src/main/java/org/apache/ibatis/binding/MapperRegistryHelper.java @@ -0,0 +1,35 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.binding; + +import java.util.Set; + +import org.apache.ibatis.io.ResolverUtil; + +public class MapperRegistryHelper { + public static void addMappers(MapperRegistry registry, String packageName, Class superType) { + ResolverUtil> resolverUtil = new ResolverUtil<>(); + resolverUtil.find(new ResolverUtil.IsA(superType), packageName); + Set>> mapperSet = resolverUtil.getClasses(); + for (Class mapperClass : mapperSet) { + registry.addMapper(mapperClass); + } + } + + public static void addMappers(MapperRegistry registry, String packageName) { + addMappers(registry, packageName, Object.class); + } +} diff --git a/src/main/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactory.java b/src/main/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactory.java index 34ea4d6ba9b..5565cca2aa4 100644 --- a/src/main/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactory.java +++ b/src/main/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2022 the original author or authors. + * Copyright 2009-2024 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. @@ -31,9 +31,9 @@ */ public class JndiDataSourceFactory implements DataSourceFactory { - public static final String INITIAL_CONTEXT = "initial_context"; - public static final String DATA_SOURCE = "data_source"; - public static final String ENV_PREFIX = "env."; + private static final String INITIAL_CONTEXT = "initial_context"; + private static final String DATA_SOURCE = "data_source"; + private static final String ENV_PREFIX = "env."; private DataSource dataSource; @@ -81,4 +81,16 @@ private static Properties getEnvProperties(Properties allProps) { return contextProperties; } + public static String getInitialContext() { + return INITIAL_CONTEXT; + } + + public static String getDataSourceString() { + return DATA_SOURCE; + } + + public static String getEnvPrefix() { + return ENV_PREFIX; + } + } diff --git a/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java b/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java index 758b396be79..4ed702fb0b7 100644 --- a/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java +++ b/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -53,7 +53,7 @@ public class PooledDataSource implements DataSource { protected int poolMaximumIdleConnections = 5; protected int poolMaximumCheckoutTime = 20000; protected int poolTimeToWait = 20000; - protected int poolMaximumLocalBadConnectionTolerance = 3; + protected int maxBadConnTolerance = 3; protected String poolPingQuery = "NO PING QUERY SET"; protected boolean poolPingEnabled; protected int poolPingConnectionsNotUsedFor; @@ -206,7 +206,7 @@ public void setPoolMaximumIdleConnections(int poolMaximumIdleConnections) { * @since 3.4.5 */ public void setPoolMaximumLocalBadConnectionTolerance(int poolMaximumLocalBadConnectionTolerance) { - this.poolMaximumLocalBadConnectionTolerance = poolMaximumLocalBadConnectionTolerance; + this.maxBadConnTolerance = poolMaximumLocalBadConnectionTolerance; } /** @@ -313,7 +313,7 @@ public int getPoolMaximumIdleConnections() { } public int getPoolMaximumLocalBadConnectionTolerance() { - return poolMaximumLocalBadConnectionTolerance; + return maxBadConnTolerance; } public int getPoolMaximumCheckoutTime() { @@ -525,7 +525,7 @@ private PooledConnection popConnection(String username, String password) throws state.badConnectionCount++; localBadConnectionCount++; conn = null; - if (localBadConnectionCount > poolMaximumIdleConnections + poolMaximumLocalBadConnectionTolerance) { + if (localBadConnectionCount > poolMaximumIdleConnections + maxBadConnTolerance) { if (log.isDebugEnabled()) { log.debug("PooledDataSource: Could not get a good connection to the database."); } diff --git a/src/main/java/org/apache/ibatis/mapping/BooleanPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/BooleanPropertySetter.java new file mode 100644 index 00000000000..eca7cb1ec07 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/BooleanPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class BooleanPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Boolean.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/BytePropertySetter.java b/src/main/java/org/apache/ibatis/mapping/BytePropertySetter.java new file mode 100644 index 00000000000..1dfe8b47073 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/BytePropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class BytePropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Byte.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/CacheBuilder.java b/src/main/java/org/apache/ibatis/mapping/CacheBuilder.java index 26b8cae45ea..af4e4cb6c99 100644 --- a/src/main/java/org/apache/ibatis/mapping/CacheBuilder.java +++ b/src/main/java/org/apache/ibatis/mapping/CacheBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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,7 @@ package org.apache.ibatis.mapping; import java.lang.reflect.Constructor; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; import org.apache.ibatis.builder.InitializingObject; import org.apache.ibatis.cache.Cache; @@ -37,6 +34,7 @@ /** * @author Clinton Begin */ + public class CacheBuilder { private final String id; private Class implementation; @@ -47,6 +45,26 @@ public class CacheBuilder { private Properties properties; private boolean blocking; + private static final Map, PropertySetter> propertySetters = new HashMap<>(); + + static { + propertySetters.put(String.class, new StringPropertySetter()); + propertySetters.put(Integer.class, new IntegerPropertySetter()); + propertySetters.put(int.class, new IntegerPropertySetter()); + propertySetters.put(Long.class, new LongPropertySetter()); + propertySetters.put(long.class, new LongPropertySetter()); + propertySetters.put(Short.class, new ShortPropertySetter()); + propertySetters.put(short.class, new ShortPropertySetter()); + propertySetters.put(Byte.class, new BytePropertySetter()); + propertySetters.put(byte.class, new BytePropertySetter()); + propertySetters.put(Float.class, new FloatPropertySetter()); + propertySetters.put(float.class, new FloatPropertySetter()); + propertySetters.put(Boolean.class, new BooleanPropertySetter()); + propertySetters.put(boolean.class, new BooleanPropertySetter()); + propertySetters.put(Double.class, new DoublePropertySetter()); + propertySetters.put(double.class, new DoublePropertySetter()); + } + public CacheBuilder(String id) { this.id = id; this.decorators = new ArrayList<>(); @@ -93,7 +111,6 @@ public Cache build() { setDefaultImplementations(); Cache cache = newBaseCacheInstance(implementation, id); setCacheProperties(cache); - // issue #352, do not apply decorators to custom caches if (PerpetualCache.class.equals(cache.getClass())) { for (Class decorator : decorators) { cache = newCacheDecoratorInstance(decorator, cache); @@ -147,22 +164,9 @@ private void setCacheProperties(Cache cache) { String value = (String) entry.getValue(); if (metaCache.hasSetter(name)) { Class type = metaCache.getSetterType(name); - if (String.class == type) { - metaCache.setValue(name, value); - } else if (int.class == type || Integer.class == type) { - metaCache.setValue(name, Integer.valueOf(value)); - } else if (long.class == type || Long.class == type) { - metaCache.setValue(name, Long.valueOf(value)); - } else if (short.class == type || Short.class == type) { - metaCache.setValue(name, Short.valueOf(value)); - } else if (byte.class == type || Byte.class == type) { - metaCache.setValue(name, Byte.valueOf(value)); - } else if (float.class == type || Float.class == type) { - metaCache.setValue(name, Float.valueOf(value)); - } else if (boolean.class == type || Boolean.class == type) { - metaCache.setValue(name, Boolean.valueOf(value)); - } else if (double.class == type || Double.class == type) { - metaCache.setValue(name, Double.valueOf(value)); + PropertySetter setter = propertySetters.get(type); + if (setter != null) { + setter.setProperty(metaCache, name, value); } else { throw new CacheException("Unsupported property type for cache: '" + name + "' of type " + type); } diff --git a/src/main/java/org/apache/ibatis/mapping/DoublePropertySetter.java b/src/main/java/org/apache/ibatis/mapping/DoublePropertySetter.java new file mode 100644 index 00000000000..427f323a1b4 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/DoublePropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class DoublePropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Double.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/FloatPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/FloatPropertySetter.java new file mode 100644 index 00000000000..1298b8c07f5 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/FloatPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class FloatPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Float.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/IntegerPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/IntegerPropertySetter.java new file mode 100644 index 00000000000..21f56bfc103 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/IntegerPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class IntegerPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Integer.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/LongPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/LongPropertySetter.java new file mode 100644 index 00000000000..18794b0264b --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/LongPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class LongPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Long.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/MappedStatement.java b/src/main/java/org/apache/ibatis/mapping/MappedStatement.java index 46ac1849f9b..78d769d9e8e 100644 --- a/src/main/java/org/apache/ibatis/mapping/MappedStatement.java +++ b/src/main/java/org/apache/ibatis/mapping/MappedStatement.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -33,303 +33,252 @@ */ public final class MappedStatement { - private String resource; - private Configuration configuration; - private String id; - private Integer fetchSize; - private Integer timeout; - private StatementType statementType; - private ResultSetType resultSetType; - private SqlSource sqlSource; - private Cache cache; - private ParameterMap parameterMap; - private List resultMaps; - private boolean flushCacheRequired; - private boolean useCache; - private boolean resultOrdered; - private SqlCommandType sqlCommandType; - private KeyGenerator keyGenerator; - private String[] keyProperties; - private String[] keyColumns; - private boolean hasNestedResultMaps; - private String databaseId; - private Log statementLog; - private LanguageDriver lang; - private String[] resultSets; - private boolean dirtySelect; - - MappedStatement() { - // constructor disabled + private final MappedStatementProperties properties; + + private MappedStatement(MappedStatementProperties properties) { + this.properties = properties; } public static class Builder { - private final MappedStatement mappedStatement = new MappedStatement(); + private final MappedStatementProperties properties = new MappedStatementProperties(); public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) { - mappedStatement.configuration = configuration; - mappedStatement.id = id; - mappedStatement.sqlSource = sqlSource; - mappedStatement.statementType = StatementType.PREPARED; - mappedStatement.resultSetType = ResultSetType.DEFAULT; - mappedStatement.parameterMap = new ParameterMap.Builder(configuration, "defaultParameterMap", null, - new ArrayList<>()).build(); - mappedStatement.resultMaps = new ArrayList<>(); - mappedStatement.sqlCommandType = sqlCommandType; - mappedStatement.keyGenerator = configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) - ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE; + properties.setConfiguration(configuration); + properties.setId(id); + properties.setSqlSource(sqlSource); + properties.setSqlCommandType(sqlCommandType); + properties.setStatementType(StatementType.PREPARED); + properties.setResultSetType(ResultSetType.DEFAULT); + properties.setParameterMap( + new ParameterMap.Builder(configuration, "defaultParameterMap", null, new ArrayList<>()).build()); + properties.setResultMaps(new ArrayList<>()); + properties.setKeyGenerator(configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) + ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE); String logId = id; if (configuration.getLogPrefix() != null) { logId = configuration.getLogPrefix() + id; } - mappedStatement.statementLog = LogFactory.getLog(logId); - mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance(); + properties.setStatementLog(LogFactory.getLog(logId)); + properties.setLang(configuration.getDefaultScriptingLanguageInstance()); } public Builder resource(String resource) { - mappedStatement.resource = resource; + properties.setResource(resource); return this; } public String id() { - return mappedStatement.id; + return properties.getId(); } public Builder parameterMap(ParameterMap parameterMap) { - mappedStatement.parameterMap = parameterMap; + properties.setParameterMap(parameterMap); return this; } public Builder resultMaps(List resultMaps) { - mappedStatement.resultMaps = resultMaps; + properties.setResultMaps(resultMaps); for (ResultMap resultMap : resultMaps) { - mappedStatement.hasNestedResultMaps = mappedStatement.hasNestedResultMaps || resultMap.hasNestedResultMaps(); + properties.setHasNestedResultMaps(properties.isHasNestedResultMaps() || resultMap.hasNestedResultMaps()); } return this; } public Builder fetchSize(Integer fetchSize) { - mappedStatement.fetchSize = fetchSize; + properties.setFetchSize(fetchSize); return this; } public Builder timeout(Integer timeout) { - mappedStatement.timeout = timeout; + properties.setTimeout(timeout); return this; } public Builder statementType(StatementType statementType) { - mappedStatement.statementType = statementType; + properties.setStatementType(statementType); return this; } public Builder resultSetType(ResultSetType resultSetType) { - mappedStatement.resultSetType = resultSetType == null ? ResultSetType.DEFAULT : resultSetType; + properties.setResultSetType(resultSetType == null ? ResultSetType.DEFAULT : resultSetType); return this; } public Builder cache(Cache cache) { - mappedStatement.cache = cache; + properties.setCache(cache); return this; } public Builder flushCacheRequired(boolean flushCacheRequired) { - mappedStatement.flushCacheRequired = flushCacheRequired; + properties.setFlushCacheRequired(flushCacheRequired); return this; } public Builder useCache(boolean useCache) { - mappedStatement.useCache = useCache; + properties.setUseCache(useCache); return this; } public Builder resultOrdered(boolean resultOrdered) { - mappedStatement.resultOrdered = resultOrdered; + properties.setResultOrdered(resultOrdered); return this; } public Builder keyGenerator(KeyGenerator keyGenerator) { - mappedStatement.keyGenerator = keyGenerator; + properties.setKeyGenerator(keyGenerator); return this; } public Builder keyProperty(String keyProperty) { - mappedStatement.keyProperties = delimitedStringToArray(keyProperty); + properties.setKeyProperties(delimitedStringToArray(keyProperty)); return this; } public Builder keyColumn(String keyColumn) { - mappedStatement.keyColumns = delimitedStringToArray(keyColumn); + properties.setKeyColumns(delimitedStringToArray(keyColumn)); return this; } public Builder databaseId(String databaseId) { - mappedStatement.databaseId = databaseId; + properties.setDatabaseId(databaseId); return this; } public Builder lang(LanguageDriver driver) { - mappedStatement.lang = driver; + properties.setLang(driver); return this; } public Builder resultSets(String resultSet) { - mappedStatement.resultSets = delimitedStringToArray(resultSet); + properties.setResultSets(delimitedStringToArray(resultSet)); return this; } public Builder dirtySelect(boolean dirtySelect) { - mappedStatement.dirtySelect = dirtySelect; - return this; - } - - /** - * Resul sets. - * - * @param resultSet - * the result set - * - * @return the builder - * - * @deprecated Use {@link #resultSets} - */ - @Deprecated - public Builder resulSets(String resultSet) { - mappedStatement.resultSets = delimitedStringToArray(resultSet); + properties.setDirtySelect(dirtySelect); return this; } public MappedStatement build() { - assert mappedStatement.configuration != null; - assert mappedStatement.id != null; - assert mappedStatement.sqlSource != null; - assert mappedStatement.lang != null; - mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps); - return mappedStatement; + assert properties.getConfiguration() != null; + assert properties.getId() != null; + assert properties.getSqlSource() != null; + assert properties.getLang() != null; + properties.setResultMaps(Collections.unmodifiableList(properties.getResultMaps())); + return new MappedStatement(properties); } } public KeyGenerator getKeyGenerator() { - return keyGenerator; + return properties.getKeyGenerator(); } public SqlCommandType getSqlCommandType() { - return sqlCommandType; + return properties.getSqlCommandType(); } public String getResource() { - return resource; + return properties.getResource(); } public Configuration getConfiguration() { - return configuration; + return properties.getConfiguration(); } public String getId() { - return id; + return properties.getId(); } public boolean hasNestedResultMaps() { - return hasNestedResultMaps; + return properties.isHasNestedResultMaps(); } public Integer getFetchSize() { - return fetchSize; + return properties.getFetchSize(); } public Integer getTimeout() { - return timeout; + return properties.getTimeout(); } public StatementType getStatementType() { - return statementType; + return properties.getStatementType(); } public ResultSetType getResultSetType() { - return resultSetType; + return properties.getResultSetType(); } public SqlSource getSqlSource() { - return sqlSource; + return properties.getSqlSource(); } public ParameterMap getParameterMap() { - return parameterMap; + return properties.getParameterMap(); } public List getResultMaps() { - return resultMaps; + return properties.getResultMaps(); } public Cache getCache() { - return cache; + return properties.getCache(); } public boolean isFlushCacheRequired() { - return flushCacheRequired; + return properties.isFlushCacheRequired(); } public boolean isUseCache() { - return useCache; + return properties.isUseCache(); } public boolean isResultOrdered() { - return resultOrdered; + return properties.isResultOrdered(); } public String getDatabaseId() { - return databaseId; + return properties.getDatabaseId(); } public String[] getKeyProperties() { - return keyProperties; + return properties.getKeyProperties(); } public String[] getKeyColumns() { - return keyColumns; + return properties.getKeyColumns(); } public Log getStatementLog() { - return statementLog; + return properties.getStatementLog(); } public LanguageDriver getLang() { - return lang; + return properties.getLang(); } public String[] getResultSets() { - return resultSets; + return properties.getResultSets(); } public boolean isDirtySelect() { - return dirtySelect; - } - - /** - * Gets the resul sets. - * - * @return the resul sets - * - * @deprecated Use {@link #getResultSets()} - */ - @Deprecated - public String[] getResulSets() { - return resultSets; + return properties.isDirtySelect(); } public BoundSql getBoundSql(Object parameterObject) { - BoundSql boundSql = sqlSource.getBoundSql(parameterObject); + BoundSql boundSql = properties.getSqlSource().getBoundSql(parameterObject); List parameterMappings = boundSql.getParameterMappings(); if (parameterMappings == null || parameterMappings.isEmpty()) { - boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); + boundSql = new BoundSql(properties.getConfiguration(), boundSql.getSql(), + properties.getParameterMap().getParameterMappings(), parameterObject); } - // check for nested result maps in parameter mappings (issue #30) for (ParameterMapping pm : boundSql.getParameterMappings()) { String rmId = pm.getResultMapId(); if (rmId != null) { - ResultMap rm = configuration.getResultMap(rmId); + ResultMap rm = properties.getConfiguration().getResultMap(rmId); if (rm != null) { - hasNestedResultMaps |= rm.hasNestedResultMaps(); + properties.setHasNestedResultMaps(properties.isHasNestedResultMaps() || rm.hasNestedResultMaps()); } } } @@ -343,5 +292,4 @@ private static String[] delimitedStringToArray(String in) { } return in.split(","); } - } diff --git a/src/main/java/org/apache/ibatis/mapping/MappedStatementProperties.java b/src/main/java/org/apache/ibatis/mapping/MappedStatementProperties.java new file mode 100644 index 00000000000..d281d3285f4 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/MappedStatementProperties.java @@ -0,0 +1,246 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import java.util.List; + +import org.apache.ibatis.cache.Cache; +import org.apache.ibatis.executor.keygen.KeyGenerator; +import org.apache.ibatis.logging.Log; +import org.apache.ibatis.scripting.LanguageDriver; +import org.apache.ibatis.session.Configuration; + +public class MappedStatementProperties { + + private String resource; + private Configuration configuration; + private String id; + private Integer fetchSize; + private Integer timeout; + private StatementType statementType; + private ResultSetType resultSetType; + private SqlSource sqlSource; + private Cache cache; + private ParameterMap parameterMap; + private List resultMaps; + private boolean flushCacheRequired; + private boolean useCache; + private boolean resultOrdered; + private SqlCommandType sqlCommandType; + private KeyGenerator keyGenerator; + private String[] keyProperties; + private String[] keyColumns; + private boolean hasNestedResultMaps; + private String databaseId; + private Log statementLog; + private LanguageDriver lang; + private String[] resultSets; + private boolean dirtySelect; + + // Getters and setters for all properties + + public String getResource() { + return resource; + } + + public void setResource(String resource) { + this.resource = resource; + } + + public Configuration getConfiguration() { + return configuration; + } + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Integer getFetchSize() { + return fetchSize; + } + + public void setFetchSize(Integer fetchSize) { + this.fetchSize = fetchSize; + } + + public Integer getTimeout() { + return timeout; + } + + public void setTimeout(Integer timeout) { + this.timeout = timeout; + } + + public StatementType getStatementType() { + return statementType; + } + + public void setStatementType(StatementType statementType) { + this.statementType = statementType; + } + + public ResultSetType getResultSetType() { + return resultSetType; + } + + public void setResultSetType(ResultSetType resultSetType) { + this.resultSetType = resultSetType; + } + + public SqlSource getSqlSource() { + return sqlSource; + } + + public void setSqlSource(SqlSource sqlSource) { + this.sqlSource = sqlSource; + } + + public Cache getCache() { + return cache; + } + + public void setCache(Cache cache) { + this.cache = cache; + } + + public ParameterMap getParameterMap() { + return parameterMap; + } + + public void setParameterMap(ParameterMap parameterMap) { + this.parameterMap = parameterMap; + } + + public List getResultMaps() { + return resultMaps; + } + + public void setResultMaps(List resultMaps) { + this.resultMaps = resultMaps; + } + + public boolean isFlushCacheRequired() { + return flushCacheRequired; + } + + public void setFlushCacheRequired(boolean flushCacheRequired) { + this.flushCacheRequired = flushCacheRequired; + } + + public boolean isUseCache() { + return useCache; + } + + public void setUseCache(boolean useCache) { + this.useCache = useCache; + } + + public boolean isResultOrdered() { + return resultOrdered; + } + + public void setResultOrdered(boolean resultOrdered) { + this.resultOrdered = resultOrdered; + } + + public SqlCommandType getSqlCommandType() { + return sqlCommandType; + } + + public void setSqlCommandType(SqlCommandType sqlCommandType) { + this.sqlCommandType = sqlCommandType; + } + + public KeyGenerator getKeyGenerator() { + return keyGenerator; + } + + public void setKeyGenerator(KeyGenerator keyGenerator) { + this.keyGenerator = keyGenerator; + } + + public String[] getKeyProperties() { + return keyProperties; + } + + public void setKeyProperties(String[] keyProperties) { + this.keyProperties = keyProperties; + } + + public String[] getKeyColumns() { + return keyColumns; + } + + public void setKeyColumns(String[] keyColumns) { + this.keyColumns = keyColumns; + } + + public boolean isHasNestedResultMaps() { + return hasNestedResultMaps; + } + + public void setHasNestedResultMaps(boolean hasNestedResultMaps) { + this.hasNestedResultMaps = hasNestedResultMaps; + } + + public String getDatabaseId() { + return databaseId; + } + + public void setDatabaseId(String databaseId) { + this.databaseId = databaseId; + } + + public Log getStatementLog() { + return statementLog; + } + + public void setStatementLog(Log statementLog) { + this.statementLog = statementLog; + } + + public LanguageDriver getLang() { + return lang; + } + + public void setLang(LanguageDriver lang) { + this.lang = lang; + } + + public String[] getResultSets() { + return resultSets; + } + + public void setResultSets(String[] resultSets) { + this.resultSets = resultSets; + } + + public boolean isDirtySelect() { + return dirtySelect; + } + + public void setDirtySelect(boolean dirtySelect) { + this.dirtySelect = dirtySelect; + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/ParameterMapping.java b/src/main/java/org/apache/ibatis/mapping/ParameterMapping.java index 040e182a8cd..c49d6070116 100644 --- a/src/main/java/org/apache/ibatis/mapping/ParameterMapping.java +++ b/src/main/java/org/apache/ibatis/mapping/ParameterMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -27,35 +27,32 @@ */ public class ParameterMapping { - private Configuration configuration; - + private ParameterMappingConfig config; private String property; private ParameterMode mode; - private Class javaType = Object.class; - private JdbcType jdbcType; private Integer numericScale; - private TypeHandler typeHandler; private String resultMapId; private String jdbcTypeName; private String expression; private ParameterMapping() { + this.config = new ParameterMappingConfig(); } public static class Builder { private final ParameterMapping parameterMapping = new ParameterMapping(); public Builder(Configuration configuration, String property, TypeHandler typeHandler) { - parameterMapping.configuration = configuration; + parameterMapping.config.setConfiguration(configuration); parameterMapping.property = property; - parameterMapping.typeHandler = typeHandler; + parameterMapping.config.setTypeHandler(typeHandler); parameterMapping.mode = ParameterMode.IN; } public Builder(Configuration configuration, String property, Class javaType) { - parameterMapping.configuration = configuration; + parameterMapping.config.setConfiguration(configuration); parameterMapping.property = property; - parameterMapping.javaType = javaType; + parameterMapping.config.setJavaType(javaType); parameterMapping.mode = ParameterMode.IN; } @@ -65,12 +62,12 @@ public Builder mode(ParameterMode mode) { } public Builder javaType(Class javaType) { - parameterMapping.javaType = javaType; + parameterMapping.config.setJavaType(javaType); return this; } public Builder jdbcType(JdbcType jdbcType) { - parameterMapping.jdbcType = jdbcType; + parameterMapping.config.setJdbcType(jdbcType); return this; } @@ -85,7 +82,7 @@ public Builder resultMapId(String resultMapId) { } public Builder typeHandler(TypeHandler typeHandler) { - parameterMapping.typeHandler = typeHandler; + parameterMapping.config.setTypeHandler(typeHandler); return this; } @@ -106,101 +103,61 @@ public ParameterMapping build() { } private void validate() { - if (ResultSet.class.equals(parameterMapping.javaType)) { + if (ResultSet.class.equals(parameterMapping.config.getJavaType())) { if (parameterMapping.resultMapId == null) { throw new IllegalStateException("Missing resultmap in property '" + parameterMapping.property + "'. " + "Parameters of type java.sql.ResultSet require a resultmap."); } - } else if (parameterMapping.typeHandler == null) { + } else if (parameterMapping.config.getTypeHandler() == null) { throw new IllegalStateException("Type handler was null on parameter mapping for property '" + parameterMapping.property + "'. It was either not specified and/or could not be found for the javaType (" - + parameterMapping.javaType.getName() + ") : jdbcType (" + parameterMapping.jdbcType + ") combination."); + + parameterMapping.config.getJavaType().getName() + ") : jdbcType (" + parameterMapping.config.getJdbcType() + + ") combination."); } } private void resolveTypeHandler() { - if (parameterMapping.typeHandler == null && parameterMapping.javaType != null) { - Configuration configuration = parameterMapping.configuration; + if (parameterMapping.config.getTypeHandler() == null && parameterMapping.config.getJavaType() != null) { + Configuration configuration = parameterMapping.config.getConfiguration(); TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry(); - parameterMapping.typeHandler = typeHandlerRegistry.getTypeHandler(parameterMapping.javaType, - parameterMapping.jdbcType); + parameterMapping.config.setTypeHandler(typeHandlerRegistry.getTypeHandler(parameterMapping.config.getJavaType(), + parameterMapping.config.getJdbcType())); } } - } public String getProperty() { return property; } - /** - * Used for handling output of callable statements. - * - * @return the mode - */ public ParameterMode getMode() { return mode; } - /** - * Used for handling output of callable statements. - * - * @return the java type - */ public Class getJavaType() { - return javaType; + return config.getJavaType(); } - /** - * Used in the UnknownTypeHandler in case there is no handler for the property type. - * - * @return the jdbc type - */ public JdbcType getJdbcType() { - return jdbcType; + return config.getJdbcType(); } - /** - * Used for handling output of callable statements. - * - * @return the numeric scale - */ public Integer getNumericScale() { return numericScale; } - /** - * Used when setting parameters to the PreparedStatement. - * - * @return the type handler - */ public TypeHandler getTypeHandler() { - return typeHandler; + return config.getTypeHandler(); } - /** - * Used for handling output of callable statements. - * - * @return the result map id - */ public String getResultMapId() { return resultMapId; } - /** - * Used for handling output of callable statements. - * - * @return the jdbc type name - */ public String getJdbcTypeName() { return jdbcTypeName; } - /** - * Expression 'Not used'. - * - * @return the expression - */ public String getExpression() { return expression; } @@ -208,13 +165,11 @@ public String getExpression() { @Override public String toString() { final StringBuilder sb = new StringBuilder("ParameterMapping{"); - // sb.append("configuration=").append(configuration); // configuration doesn't have a useful .toString() sb.append("property='").append(property).append('\''); sb.append(", mode=").append(mode); - sb.append(", javaType=").append(javaType); - sb.append(", jdbcType=").append(jdbcType); + sb.append(", javaType=").append(config.getJavaType()); + sb.append(", jdbcType=").append(config.getJdbcType()); sb.append(", numericScale=").append(numericScale); - // sb.append(", typeHandler=").append(typeHandler); // typeHandler also doesn't have a useful .toString() sb.append(", resultMapId='").append(resultMapId).append('\''); sb.append(", jdbcTypeName='").append(jdbcTypeName).append('\''); sb.append(", expression='").append(expression).append('\''); diff --git a/src/main/java/org/apache/ibatis/mapping/ParameterMappingConfig.java b/src/main/java/org/apache/ibatis/mapping/ParameterMappingConfig.java new file mode 100644 index 00000000000..1efc6c868e3 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/ParameterMappingConfig.java @@ -0,0 +1,62 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.session.Configuration; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.TypeHandler; + +public class ParameterMappingConfig { + + private Configuration configuration; + private Class javaType = Object.class; + private JdbcType jdbcType; + private TypeHandler typeHandler; + + // Getters and setters for all properties + + public Configuration getConfiguration() { + return configuration; + } + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public Class getJavaType() { + return javaType; + } + + public void setJavaType(Class javaType) { + this.javaType = javaType; + } + + public JdbcType getJdbcType() { + return jdbcType; + } + + public void setJdbcType(JdbcType jdbcType) { + this.jdbcType = jdbcType; + } + + public TypeHandler getTypeHandler() { + return typeHandler; + } + + public void setTypeHandler(TypeHandler typeHandler) { + this.typeHandler = typeHandler; + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/PropertySetter.java b/src/main/java/org/apache/ibatis/mapping/PropertySetter.java new file mode 100644 index 00000000000..c6e6d3592a8 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/PropertySetter.java @@ -0,0 +1,22 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public interface PropertySetter { + void setProperty(MetaObject metaCache, String name, String value); +} diff --git a/src/main/java/org/apache/ibatis/mapping/ResultMap.java b/src/main/java/org/apache/ibatis/mapping/ResultMap.java index a4f7d4ae57a..4eb90a05169 100644 --- a/src/main/java/org/apache/ibatis/mapping/ResultMap.java +++ b/src/main/java/org/apache/ibatis/mapping/ResultMap.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -206,6 +206,13 @@ private List getArgNames(Constructor constructor) { } } + public static void validateNestedQueryAndResultMap(ResultMapping resultMapping) { + if (resultMapping.getNestedQueryId() != null && resultMapping.getNestedResultMapId() != null) { + throw new IllegalStateException( + "Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.getProperty()); + } + } + public String getId() { return id; } diff --git a/src/main/java/org/apache/ibatis/mapping/ResultMapping.java b/src/main/java/org/apache/ibatis/mapping/ResultMapping.java index ffa715c596f..8c59d0ce30f 100644 --- a/src/main/java/org/apache/ibatis/mapping/ResultMapping.java +++ b/src/main/java/org/apache/ibatis/mapping/ResultMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -15,6 +15,8 @@ */ package org.apache.ibatis.mapping; +import static org.apache.ibatis.mapping.ResultMap.validateNestedQueryAndResultMap; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -142,21 +144,27 @@ public ResultMapping build() { } private void validate() { - // Issue #697: cannot define both nestedQueryId and nestedResultMapId - if (resultMapping.nestedQueryId != null && resultMapping.nestedResultMapId != null) { - throw new IllegalStateException( - "Cannot define both nestedQueryId and nestedResultMapId in property " + resultMapping.property); - } - // Issue #5: there should be no mappings without typehandler + validateNestedQueryAndResultMap(resultMapping); + validateTypeHandler(); + validateColumn(); + validateResultSet(); + } + + private void validateTypeHandler() { if (resultMapping.nestedQueryId == null && resultMapping.nestedResultMapId == null && resultMapping.typeHandler == null) { throw new IllegalStateException("No typehandler found for property " + resultMapping.property); } - // Issue #4 and GH #39: column is optional only in nested resultmaps but not in the rest + } + + private void validateColumn() { if (resultMapping.nestedResultMapId == null && resultMapping.column == null && resultMapping.composites.isEmpty()) { throw new IllegalStateException("Mapping is missing column attribute for property " + resultMapping.property); } + } + + private void validateResultSet() { if (resultMapping.getResultSet() != null) { int numColumns = 0; if (resultMapping.column != null) { diff --git a/src/main/java/org/apache/ibatis/mapping/ShortPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/ShortPropertySetter.java new file mode 100644 index 00000000000..3fc67a0ca82 --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/ShortPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class ShortPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, Short.valueOf(value)); + } +} diff --git a/src/main/java/org/apache/ibatis/mapping/StringPropertySetter.java b/src/main/java/org/apache/ibatis/mapping/StringPropertySetter.java new file mode 100644 index 00000000000..5fafc3d3a9e --- /dev/null +++ b/src/main/java/org/apache/ibatis/mapping/StringPropertySetter.java @@ -0,0 +1,25 @@ +/* + * Copyright 2009-2024 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ibatis.mapping; + +import org.apache.ibatis.reflection.MetaObject; + +public class StringPropertySetter implements PropertySetter { + @Override + public void setProperty(MetaObject metaCache, String name, String value) { + metaCache.setValue(name, value); + } +} diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java index ae60c8808fb..2b8c1ae433c 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -31,8 +31,8 @@ */ public class DynamicContext { - public static final String PARAMETER_OBJECT_KEY = "_parameter"; - public static final String DATABASE_ID_KEY = "_databaseId"; + private static final String PARAMETER_OBJECT_KEY = "_parameter"; + private static final String DATABASE_ID_KEY = "_databaseId"; static { OgnlRuntime.setPropertyAccessor(ContextMap.class, new ContextAccessor()); diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/ForEachSqlNode.java b/src/main/java/org/apache/ibatis/scripting/xmltags/ForEachSqlNode.java index 30dfb631c9f..0e864e10626 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/ForEachSqlNode.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/ForEachSqlNode.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -25,7 +25,7 @@ * @author Clinton Begin */ public class ForEachSqlNode implements SqlNode { - public static final String ITEM_PREFIX = "__frch_"; + private static final String ITEM_PREFIX = "__frch_"; private final ExpressionEvaluator evaluator; private final String collectionExpression; diff --git a/src/test/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactoryTest.java b/src/test/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactoryTest.java index 49d82ade875..29bd284cba3 100644 --- a/src/test/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactoryTest.java +++ b/src/test/java/org/apache/ibatis/datasource/jndi/JndiDataSourceFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -53,9 +53,10 @@ void shouldRetrieveDataSourceFromJNDI() { factory.setProperties(new Properties() { private static final long serialVersionUID = 1L; { - setProperty(JndiDataSourceFactory.ENV_PREFIX + Context.INITIAL_CONTEXT_FACTORY, TEST_INITIAL_CONTEXT_FACTORY); - setProperty(JndiDataSourceFactory.INITIAL_CONTEXT, TEST_INITIAL_CONTEXT); - setProperty(JndiDataSourceFactory.DATA_SOURCE, TEST_DATA_SOURCE); + setProperty(JndiDataSourceFactory.getEnvPrefix() + Context.INITIAL_CONTEXT_FACTORY, + TEST_INITIAL_CONTEXT_FACTORY); + setProperty(JndiDataSourceFactory.getInitialContext(), TEST_INITIAL_CONTEXT); + setProperty(JndiDataSourceFactory.getDataSourceString(), TEST_DATA_SOURCE); } }); DataSource actualDataSource = factory.getDataSource(); diff --git a/src/test/java/org/apache/ibatis/type/BlobInputStreamTypeHandlerTest.java b/src/test/java/org/apache/ibatis/type/BlobInputStreamTypeHandlerTest.java index c18bd75f5b3..125a8d44c57 100644 --- a/src/test/java/org/apache/ibatis/type/BlobInputStreamTypeHandlerTest.java +++ b/src/test/java/org/apache/ibatis/type/BlobInputStreamTypeHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -60,7 +60,8 @@ class BlobInputStreamTypeHandlerTest extends BaseTypeHandlerTest { @BeforeAll static void setupSqlSessionFactory() throws Exception { - DataSource dataSource = BaseDataTest.createUnpooledDataSource("org/apache/ibatis/type/jdbc.properties"); + DataSource dataSource = (DataSource) BaseDataTest + .createUnpooledDataSource("org/apache/ibatis/type/jdbc.properties"); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("Production", transactionFactory, dataSource); Configuration configuration = new Configuration(environment); diff --git a/src/test/java/org/apache/ibatis/type/ClobReaderTypeHandlerTest.java b/src/test/java/org/apache/ibatis/type/ClobReaderTypeHandlerTest.java index cbc095737e4..d8385d666f7 100644 --- a/src/test/java/org/apache/ibatis/type/ClobReaderTypeHandlerTest.java +++ b/src/test/java/org/apache/ibatis/type/ClobReaderTypeHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2009-2023 the original author or authors. + * Copyright 2009-2024 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. @@ -61,7 +61,8 @@ class ClobReaderTypeHandlerTest extends BaseTypeHandlerTest { @BeforeAll static void setupSqlSessionFactory() throws Exception { - DataSource dataSource = BaseDataTest.createUnpooledDataSource("org/apache/ibatis/type/jdbc.properties"); + DataSource dataSource = (DataSource) BaseDataTest + .createUnpooledDataSource("org/apache/ibatis/type/jdbc.properties"); TransactionFactory transactionFactory = new JdbcTransactionFactory(); Environment environment = new Environment("Production", transactionFactory, dataSource); Configuration configuration = new Configuration(environment);