Merge branch '5.2.x'

# Conflicts:
#	spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java
This commit is contained in:
Juergen Hoeller 2020-09-05 13:02:01 +02:00
commit 9d7849c539
5 changed files with 76 additions and 16 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -348,8 +348,8 @@ public class MethodReference extends SpelNodeImpl {
generateCodeForArguments(mv, cf, method, this.children); generateCodeForArguments(mv, cf, method, this.children);
mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : (method.isDefault() ? INVOKEINTERFACE : INVOKEVIRTUAL)), mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : (method.isDefault() ? INVOKEINTERFACE : INVOKEVIRTUAL)),
classDesc, method.getName(), classDesc, method.getName(), CodeFlow.createSignatureDescriptor(method),
CodeFlow.createSignatureDescriptor(method), method.getDeclaringClass().isInterface()); method.getDeclaringClass().isInterface());
cf.pushDescriptor(this.exitTypeDescriptor); cf.pushDescriptor(this.exitTypeDescriptor);
if (this.originalPrimitiveExitTypeDescriptor != null) { if (this.originalPrimitiveExitTypeDescriptor != null) {

View File

@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class SpelCompilerTests { class SpelCompilerTests {
@Test // gh-24357 @Test // gh-24357
void expressionCompilesWhenMethodComesFromPublicInterface() { void expressionCompilesWhenMethodComesFromPublicInterface() {
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null); SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
SpelExpressionParser parser = new SpelExpressionParser(config); SpelExpressionParser parser = new SpelExpressionParser(config);
@ -50,6 +50,31 @@ class SpelCompilerTests {
IntStream.rangeClosed(1, 5).forEach(i -> assertThat(expression.getValue(component)).isEqualTo(42)); IntStream.rangeClosed(1, 5).forEach(i -> assertThat(expression.getValue(component)).isEqualTo(42));
} }
@Test // gh-25706
void defaultMethodInvocation() {
SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null);
SpelExpressionParser parser = new SpelExpressionParser(config);
StandardEvaluationContext context = new StandardEvaluationContext();
Item item = new Item();
context.setRootObject(item);
Expression expression = parser.parseExpression("#root.isEditable2()");
assertThat(SpelCompiler.compile(expression)).isFalse();
assertThat(expression.getValue(context)).isEqualTo(false);
assertThat(SpelCompiler.compile(expression)).isTrue();
SpelCompilationCoverageTests.assertIsCompiled(expression);
assertThat(expression.getValue(context)).isEqualTo(false);
context.setVariable("user", new User());
expression = parser.parseExpression("#root.isEditable(#user)");
assertThat(SpelCompiler.compile(expression)).isFalse();
assertThat(expression.getValue(context)).isEqualTo(true);
assertThat(SpelCompiler.compile(expression)).isTrue();
SpelCompilationCoverageTests.assertIsCompiled(expression);
assertThat(expression.getValue(context)).isEqualTo(true);
}
static class OrderedComponent implements Ordered { static class OrderedComponent implements Ordered {
@ -114,4 +139,40 @@ class SpelCompilerTests {
boolean hasSomeProperty(); boolean hasSomeProperty();
} }
public static class User {
boolean isAdmin() {
return true;
}
}
public static class Item implements Editable {
// some fields
private String someField = "";
// some getters and setters
@Override
public boolean hasSomeProperty() {
return someField != null;
}
}
public interface Editable {
default boolean isEditable(User user) {
return user.isAdmin() && hasSomeProperty();
}
default boolean isEditable2() {
return false;
}
boolean hasSomeProperty();
}
} }

View File

@ -66,12 +66,11 @@ public abstract class StatementCreatorUtils {
* completely, i.e. to never even attempt to retrieve {@link PreparedStatement#getParameterMetaData()} * completely, i.e. to never even attempt to retrieve {@link PreparedStatement#getParameterMetaData()}
* for {@link StatementCreatorUtils#setNull} calls. * for {@link StatementCreatorUtils#setNull} calls.
* <p>The default is "false", trying {@code getParameterType} calls first and falling back to * <p>The default is "false", trying {@code getParameterType} calls first and falling back to
* {@link PreparedStatement#setNull} / {@link PreparedStatement#setObject} calls based on well-known * {@link PreparedStatement#setNull} / {@link PreparedStatement#setObject} calls based on
* behavior of common databases. Spring records JDBC drivers with non-working {@code getParameterType} * well-known behavior of common databases.
* implementations and won't attempt to call that method for that driver again, always falling back. * <p>Consider switching this flag to "true" if you experience misbehavior at runtime,
* <p>Consider switching this flag to "true" if you experience misbehavior at runtime, e.g. with * e.g. with connection pool issues in case of an exception thrown from {@code getParameterType}
* a connection pool setting back the {@link PreparedStatement} instance in case of an exception * (as reported on JBoss AS 7) or in case of performance problems (as reported on PostgreSQL).
* thrown from {@code getParameterType} (as reported on JBoss AS 7).
*/ */
public static final String IGNORE_GETPARAMETERTYPE_PROPERTY_NAME = "spring.jdbc.getParameterType.ignore"; public static final String IGNORE_GETPARAMETERTYPE_PROPERTY_NAME = "spring.jdbc.getParameterType.ignore";
@ -266,7 +265,7 @@ public abstract class StatementCreatorUtils {
} }
else if (databaseProductName.startsWith("DB2") || else if (databaseProductName.startsWith("DB2") ||
jdbcDriverName.startsWith("jConnect") || jdbcDriverName.startsWith("jConnect") ||
jdbcDriverName.startsWith("SQLServer")|| jdbcDriverName.startsWith("SQLServer") ||
jdbcDriverName.startsWith("Apache Derby")) { jdbcDriverName.startsWith("Apache Derby")) {
sqlTypeToUse = Types.VARCHAR; sqlTypeToUse = Types.VARCHAR;
} }

View File

@ -355,7 +355,7 @@ public class CallMetaDataContext {
logger.debug("Using declared out parameter '" + paramName + logger.debug("Using declared out parameter '" + paramName +
"' for function return value"); "' for function return value");
} }
setFunctionReturnName(paramName); this.actualFunctionReturnName = paramName;
returnDeclared = true; returnDeclared = true;
} }
} }
@ -393,8 +393,8 @@ public class CallMetaDataContext {
"Unable to locate declared parameter for function return value - " + "Unable to locate declared parameter for function return value - " +
" add an SqlOutParameter with name '" + getFunctionReturnName() + "'"); " add an SqlOutParameter with name '" + getFunctionReturnName() + "'");
} }
else if (paramName != null) { else {
setFunctionReturnName(paramName); this.actualFunctionReturnName = param.getName();
} }
} }
else { else {
@ -422,7 +422,7 @@ public class CallMetaDataContext {
(StringUtils.hasLength(paramNameToUse) ? paramNameToUse : getFunctionReturnName()); (StringUtils.hasLength(paramNameToUse) ? paramNameToUse : getFunctionReturnName());
workParams.add(provider.createDefaultOutParameter(returnNameToUse, meta)); workParams.add(provider.createDefaultOutParameter(returnNameToUse, meta));
if (isFunction()) { if (isFunction()) {
setFunctionReturnName(returnNameToUse); this.actualFunctionReturnName = returnNameToUse;
outParamNames.add(returnNameToUse); outParamNames.add(returnNameToUse);
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {

View File

@ -4452,7 +4452,7 @@ While this usually works well, there is a potential for issues (for example, wit
case, which can be expensive with your JDBC driver. You should use a recent driver case, which can be expensive with your JDBC driver. You should use a recent driver
version and consider setting the `spring.jdbc.getParameterType.ignore` property to `true` version and consider setting the `spring.jdbc.getParameterType.ignore` property to `true`
(as a JVM system property or in a `spring.properties` file in the root of your classpath) (as a JVM system property or in a `spring.properties` file in the root of your classpath)
if you encounter a performance issue -- for example, as reported on Oracle 12c (SPR-16139). if you encounter a performance issue (as reported on Oracle 12c, JBoss and PostgreSQL).
Alternatively, you might consider specifying the corresponding JDBC types explicitly, Alternatively, you might consider specifying the corresponding JDBC types explicitly,
either through a 'BatchPreparedStatementSetter' (as shown earlier), through an explicit type either through a 'BatchPreparedStatementSetter' (as shown earlier), through an explicit type