com.ibatis.sqlmap.engine.mapping.parameter.InlineParameterMapParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mybatis2 Show documentation
Show all versions of mybatis2 Show documentation
The mybatis data mapper framework makes it easier to use a relational database with object-oriented
applications. mybatis couples objects with stored procedures or SQL statements using a XML descriptor or
annotations. Simplicity is the biggest advantage of the mybatis data mapper over object relational mapping
tools.
The newest version!
/*
* Copyright 2004-2022 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 com.ibatis.sqlmap.engine.mapping.parameter;
import com.ibatis.common.beans.Probe;
import com.ibatis.common.beans.ProbeFactory;
import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapException;
import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback;
import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
import com.ibatis.sqlmap.engine.type.CustomTypeHandler;
import com.ibatis.sqlmap.engine.type.DomTypeMarker;
import com.ibatis.sqlmap.engine.type.TypeHandler;
import com.ibatis.sqlmap.engine.type.TypeHandlerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
/**
* The Class InlineParameterMapParser.
*/
public class InlineParameterMapParser {
/** The Constant PROBE. */
private static final Probe PROBE = ProbeFactory.getProbe();
/** The Constant PARAMETER_TOKEN. */
private static final String PARAMETER_TOKEN = "#";
/** The Constant PARAM_DELIM. */
private static final String PARAM_DELIM = ":";
/**
* Parses the inline parameter map.
*
* @param typeHandlerFactory
* the type handler factory
* @param sqlStatement
* the sql statement
*
* @return the sql text
*/
public SqlText parseInlineParameterMap(TypeHandlerFactory typeHandlerFactory, String sqlStatement) {
return parseInlineParameterMap(typeHandlerFactory, sqlStatement, null);
}
/**
* Parses the inline parameter map.
*
* @param typeHandlerFactory
* the type handler factory
* @param sqlStatement
* the sql statement
* @param parameterClass
* the parameter class
*
* @return the sql text
*/
public SqlText parseInlineParameterMap(TypeHandlerFactory typeHandlerFactory, String sqlStatement,
Class parameterClass) {
String newSql = sqlStatement;
List mappingList = new ArrayList();
StringTokenizer parser = new StringTokenizer(sqlStatement, PARAMETER_TOKEN, true);
StringBuilder newSqlBuffer = new StringBuilder();
String token = null;
String lastToken = null;
while (parser.hasMoreTokens()) {
token = parser.nextToken();
if (PARAMETER_TOKEN.equals(lastToken)) {
if (PARAMETER_TOKEN.equals(token)) {
newSqlBuffer.append(PARAMETER_TOKEN);
token = null;
} else {
ParameterMapping mapping = null;
if (token.indexOf(PARAM_DELIM) > -1) {
mapping = oldParseMapping(token, parameterClass, typeHandlerFactory);
} else {
mapping = newParseMapping(token, parameterClass, typeHandlerFactory);
}
mappingList.add(mapping);
newSqlBuffer.append("?");
boolean hasMoreTokens = parser.hasMoreTokens();
if (hasMoreTokens)
token = parser.nextToken();
if (!hasMoreTokens || !PARAMETER_TOKEN.equals(token)) {
throw new SqlMapException(
"Unterminated inline parameter in mapped statement near '" + newSqlBuffer.toString() + "'");
}
token = null;
}
} else {
if (!PARAMETER_TOKEN.equals(token)) {
newSqlBuffer.append(token);
}
}
lastToken = token;
}
newSql = newSqlBuffer.toString();
ParameterMapping[] mappingArray = (ParameterMapping[]) mappingList
.toArray(new ParameterMapping[mappingList.size()]);
SqlText sqlText = new SqlText();
sqlText.setText(newSql);
sqlText.setParameterMappings(mappingArray);
return sqlText;
}
/**
* New parse mapping.
*
* @param token
* the token
* @param parameterClass
* the parameter class
* @param typeHandlerFactory
* the type handler factory
*
* @return the parameter mapping
*/
private ParameterMapping newParseMapping(String token, Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
ParameterMapping mapping = new ParameterMapping();
// #propertyName,javaType=string,jdbcType=VARCHAR,mode=IN,nullValue=N/A,handler=string,numericScale=2#
StringTokenizer paramParser = new StringTokenizer(token, "=,", false);
mapping.setPropertyName(paramParser.nextToken());
while (paramParser.hasMoreTokens()) {
String field = paramParser.nextToken();
if (paramParser.hasMoreTokens()) {
String value = paramParser.nextToken();
if ("javaType".equals(field)) {
value = typeHandlerFactory.resolveAlias(value);
mapping.setJavaTypeName(value);
} else if ("jdbcType".equals(field)) {
mapping.setJdbcTypeName(value);
} else if ("mode".equals(field)) {
mapping.setMode(value);
} else if ("nullValue".equals(field)) {
mapping.setNullValue(value);
} else if ("handler".equals(field)) {
try {
value = typeHandlerFactory.resolveAlias(value);
Object impl = Resources.instantiate(value);
if (impl instanceof TypeHandlerCallback) {
mapping.setTypeHandler(new CustomTypeHandler((TypeHandlerCallback) impl));
} else if (impl instanceof TypeHandler) {
mapping.setTypeHandler((TypeHandler) impl);
} else {
throw new SqlMapException(
"The class " + value + " is not a valid implementation of TypeHandler or TypeHandlerCallback");
}
} catch (Exception e) {
throw new SqlMapException("Error loading class specified by handler field in " + token + ". Cause: " + e,
e);
}
} else if ("numericScale".equals(field)) {
try {
Integer numericScale = Integer.valueOf(value);
if (numericScale.intValue() < 0) {
throw new SqlMapException("Value specified for numericScale must be greater than or equal to zero");
}
mapping.setNumericScale(numericScale);
} catch (NumberFormatException e) {
throw new SqlMapException("Value specified for numericScale is not a valid Integer");
}
} else {
throw new SqlMapException("Unrecognized parameter mapping field: '" + field + "' in " + token);
}
} else {
throw new SqlMapException("Incorrect inline parameter map format (missmatched name=value pairs): " + token);
}
}
if (mapping.getTypeHandler() == null) {
TypeHandler handler;
if (parameterClass == null) {
handler = typeHandlerFactory.getUnkownTypeHandler();
} else {
handler = resolveTypeHandler(typeHandlerFactory, parameterClass, mapping.getPropertyName(),
mapping.getJavaTypeName(), mapping.getJdbcTypeName());
}
mapping.setTypeHandler(handler);
}
return mapping;
}
/**
* Old parse mapping.
*
* @param token
* the token
* @param parameterClass
* the parameter class
* @param typeHandlerFactory
* the type handler factory
*
* @return the parameter mapping
*/
private ParameterMapping oldParseMapping(String token, Class parameterClass, TypeHandlerFactory typeHandlerFactory) {
ParameterMapping mapping = new ParameterMapping();
if (token.indexOf(PARAM_DELIM) > -1) {
StringTokenizer paramParser = new StringTokenizer(token, PARAM_DELIM, true);
int n1 = paramParser.countTokens();
if (n1 == 3) {
String name = paramParser.nextToken();
paramParser.nextToken(); // ignore ":"
String type = paramParser.nextToken();
mapping.setPropertyName(name);
mapping.setJdbcTypeName(type);
TypeHandler handler;
if (parameterClass == null) {
handler = typeHandlerFactory.getUnkownTypeHandler();
} else {
handler = resolveTypeHandler(typeHandlerFactory, parameterClass, name, null, type);
}
mapping.setTypeHandler(handler);
return mapping;
} else if (n1 >= 5) {
String name = paramParser.nextToken();
paramParser.nextToken(); // ignore ":"
String type = paramParser.nextToken();
paramParser.nextToken(); // ignore ":"
String nullValue = paramParser.nextToken();
while (paramParser.hasMoreTokens()) {
nullValue = nullValue + paramParser.nextToken();
}
mapping.setPropertyName(name);
mapping.setJdbcTypeName(type);
mapping.setNullValue(nullValue);
TypeHandler handler;
if (parameterClass == null) {
handler = typeHandlerFactory.getUnkownTypeHandler();
} else {
handler = resolveTypeHandler(typeHandlerFactory, parameterClass, name, null, type);
}
mapping.setTypeHandler(handler);
return mapping;
} else {
throw new SqlMapException("Incorrect inline parameter map format: " + token);
}
} else {
mapping.setPropertyName(token);
TypeHandler handler;
if (parameterClass == null) {
handler = typeHandlerFactory.getUnkownTypeHandler();
} else {
handler = resolveTypeHandler(typeHandlerFactory, parameterClass, token, null, null);
}
mapping.setTypeHandler(handler);
return mapping;
}
}
/**
* Resolve type handler.
*
* @param typeHandlerFactory
* the type handler factory
* @param clazz
* the clazz
* @param propertyName
* the property name
* @param javaType
* the java type
* @param jdbcType
* the jdbc type
*
* @return the type handler
*/
private TypeHandler resolveTypeHandler(TypeHandlerFactory typeHandlerFactory, Class clazz, String propertyName,
String javaType, String jdbcType) {
TypeHandler handler = null;
if (clazz == null) {
// Unknown
handler = typeHandlerFactory.getUnkownTypeHandler();
} else if (DomTypeMarker.class.isAssignableFrom(clazz)) {
// DOM
handler = typeHandlerFactory.getTypeHandler(String.class, jdbcType);
} else if (java.util.Map.class.isAssignableFrom(clazz)) {
// Map
if (javaType == null) {
handler = typeHandlerFactory.getUnkownTypeHandler(); // BUG 1012591 -
// typeHandlerFactory.getTypeHandler(java.lang.Object.class,
// jdbcType);
} else {
try {
javaType = typeHandlerFactory.resolveAlias(javaType);
Class javaClass = Resources.classForName(javaType);
handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
} catch (Exception e) {
throw new SqlMapException("Error. Could not set TypeHandler. Cause: " + e, e);
}
}
} else if (typeHandlerFactory.getTypeHandler(clazz, jdbcType) != null) {
// Primitive
handler = typeHandlerFactory.getTypeHandler(clazz, jdbcType);
} else {
// JavaBean
if (javaType == null) {
Class type = PROBE.getPropertyTypeForGetter(clazz, propertyName);
handler = typeHandlerFactory.getTypeHandler(type, jdbcType);
} else {
try {
javaType = typeHandlerFactory.resolveAlias(javaType);
Class javaClass = Resources.classForName(javaType);
handler = typeHandlerFactory.getTypeHandler(javaClass, jdbcType);
} catch (Exception e) {
throw new SqlMapException("Error. Could not set TypeHandler. Cause: " + e, e);
}
}
}
return handler;
}
}