Merge branch '6.0.x'
This commit is contained in:
commit
2b7a9209b3
|
|
@ -19,7 +19,10 @@ package org.springframework.expression.spel.support;
|
|||
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;
|
||||
|
|
@ -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}
|
||||
|
|
@ -110,6 +115,21 @@ public class StandardTypeLocator implements TypeLocator {
|
|||
*/
|
||||
@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);
|
||||
}
|
||||
|
|
@ -125,7 +145,7 @@ public class StandardTypeLocator implements TypeLocator {
|
|||
// might be a different prefix
|
||||
}
|
||||
}
|
||||
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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.
|
||||
|
|
@ -142,16 +142,25 @@ public abstract class NamedParameterUtils {
|
|||
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(
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -330,6 +330,18 @@ public class NamedParameterUtilsTests {
|
|||
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])";
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -154,16 +154,25 @@ abstract class NamedParameterUtils {
|
|||
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(
|
||||
|
|
@ -261,7 +270,7 @@ abstract class NamedParameterUtils {
|
|||
|
||||
/**
|
||||
* 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:
|
||||
|
|
|
|||
Loading…
Reference in New Issue