Browse Source

Merge branch '6.0.x'

pull/31608/head
Juergen Hoeller 10 months ago
parent
commit
2b7a9209b3
  1. 22
      spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java
  2. 25
      spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java
  3. 14
      spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java
  4. 29
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java

22
spring-expression/src/main/java/org/springframework/expression/spel/support/StandardTypeLocator.java

@ -19,7 +19,10 @@ package org.springframework.expression.spel.support; @@ -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 { @@ -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 { @@ -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 { @@ -125,7 +145,7 @@ public class StandardTypeLocator implements TypeLocator {
// might be a different prefix
}
}
throw new SpelEvaluationException(SpelMessage.TYPE_NOT_FOUND, typeName);
return null;
}
}

25
spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterUtils.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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 { @@ -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(

14
spring-jdbc/src/test/java/org/springframework/jdbc/core/namedparam/NamedParameterUtilsTests.java

@ -1,5 +1,5 @@ @@ -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 { @@ -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])";

29
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java

@ -67,7 +67,7 @@ abstract class NamedParameterUtils { @@ -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 { @@ -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 { @@ -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 { @@ -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…
Cancel
Save