Skip to content

Commit

Permalink
Merge branch '6.0.x'
Browse files Browse the repository at this point in the history
  • Loading branch information
jhoeller committed Nov 14, 2023
2 parents 8f21479 + 99327b7 commit 2b7a920
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.SmartClassLoader;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.spel.SpelEvaluationException;
Expand Down Expand Up @@ -48,6 +51,8 @@ public class StandardTypeLocator implements TypeLocator {

private final List<String> importPrefixes = new ArrayList<>(1);

private final Map<String, Class<?>> typeCache = new ConcurrentHashMap<>();


/**
* Create a {@code StandardTypeLocator} for the default {@link ClassLoader}
Expand Down Expand Up @@ -110,6 +115,21 @@ public List<String> getImportPrefixes() {
*/
@Override
public Class<?> findType(String typeName) throws EvaluationException {
Class<?> cachedType = this.typeCache.get(typeName);
if (cachedType != null) {
return cachedType;
}
Class<?> loadedType = loadType(typeName);
if (loadedType != null &&
!(this.classLoader instanceof SmartClassLoader scl && scl.isClassReloadable(loadedType))) {
this.typeCache.put(typeName, loadedType);
return loadedType;
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
}

@Nullable
private Class<?> loadType(String typeName) {
try {
return ClassUtils.forName(typeName, this.classLoader);
}
Expand All @@ -125,7 +145,7 @@ public Class<?> findType(String typeName) throws EvaluationException {
// might be a different prefix
}
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
return null;
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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 Down Expand Up @@ -55,7 +55,7 @@ public abstract class NamedParameterUtils {
* Set of characters that qualify as parameter separators,
* indicating that a parameter name in an SQL String has ended.
*/
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^";

/**
* An index with separator flags per character code.
Expand Down Expand Up @@ -142,16 +142,25 @@ public static ParsedSql parseSqlStatement(String sql) {
j++;
}
else {
while (j < statement.length && !isParameterSeparator(statement[j])) {
boolean paramWithSquareBrackets = false;
while (j < statement.length) {
c = statement[j];
if (isParameterSeparator(c)) {
break;
}
if (c == '[') {
paramWithSquareBrackets = true;
}
else if (c == ']') {
if (!paramWithSquareBrackets) {
break;
}
paramWithSquareBrackets = false;
}
j++;
}
if (j - i > 1) {
parameter = sql.substring(i + 1, j);
if (j < statement.length && statement[j] == ']' && parameter.contains("[")) {
// preserve end bracket for index/key
j++;
parameter = sql.substring(i + 1, j);
}
namedParameterCount = addNewNamedParameter(
namedParameters, namedParameterCount, parameter);
totalParameterCount = addNamedParameter(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 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 Down Expand Up @@ -330,6 +330,18 @@ public void parseSqlStatementWithSquareBracket() {
assertThat(sqlToUse).isEqualTo("SELECT ARRAY[?]");
}

@Test // gh-31596
void paramNameWithNestedSquareBrackets() {
String sql = "insert into GeneratedAlways (id, first_name, last_name) values " +
"(:records[0].id, :records[0].firstName, :records[0].lastName), " +
"(:records[1].id, :records[1].firstName, :records[1].lastName)";

ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
assertThat(parsedSql.getParameterNames()).containsOnly(
"records[0].id", "records[0].firstName", "records[0].lastName",
"records[1].id", "records[1].firstName", "records[1].lastName");
}

@Test // gh-27925
void namedParamMapReference() {
String sql = "insert into foos (id) values (:headers[id])";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ abstract class NamedParameterUtils {
* Set of characters that qualify as parameter separators,
* indicating that a parameter name in an SQL String has ended.
*/
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^]";
private static final String PARAMETER_SEPARATORS = "\"':&,;()|=+-*%/\\<>^";

/**
* An index with separator flags per character code.
Expand All @@ -83,12 +83,12 @@ abstract class NamedParameterUtils {


// -------------------------------------------------------------------------
// Core methods used by NamedParameterSupport.
// Core methods used by NamedParameterExpander
// -------------------------------------------------------------------------

/**
* Parse the SQL statement and locate any placeholders or named parameters.
* Named parameters are substituted for a R2DBC placeholder.
* Named parameters are substituted for an R2DBC placeholder.
* @param sql the SQL statement
* @return the parsed statement, represented as {@link ParsedSql} instance
*/
Expand Down Expand Up @@ -154,16 +154,25 @@ public static ParsedSql parseSqlStatement(String sql) {
j++;
}
else {
while (j < statement.length && !isParameterSeparator(statement[j])) {
boolean paramWithSquareBrackets = false;
while (j < statement.length) {
c = statement[j];
if (isParameterSeparator(c)) {
break;
}
if (c == '[') {
paramWithSquareBrackets = true;
}
else if (c == ']') {
if (!paramWithSquareBrackets) {
break;
}
paramWithSquareBrackets = false;
}
j++;
}
if (j - i > 1) {
parameter = sql.substring(i + 1, j);
if (j < statement.length && statement[j] == ']' && parameter.contains("[")) {
// preserve end bracket for index/key
j++;
parameter = sql.substring(i + 1, j);
}
namedParameterCount = addNewNamedParameter(
namedParameters, namedParameterCount, parameter);
totalParameterCount = addNamedParameter(
Expand Down Expand Up @@ -261,7 +270,7 @@ private static int skipCommentsAndQuotes(char[] statement, int position) {

/**
* Parse the SQL statement and locate any placeholders or named parameters. Named
* parameters are substituted for a R2DBC placeholder, and any select list is expanded
* parameters are substituted for an R2DBC placeholder, and any select list is expanded
* to the required number of placeholders. Select lists may contain an array of objects,
* and in that case the placeholders will be grouped and enclosed with parentheses.
* This allows for the use of "expression lists" in the SQL statement like:
Expand Down

0 comments on commit 2b7a920

Please sign in to comment.