diff --git a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java index 68e9c434ca8..cbaf1c8d1ad 100644 --- a/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java +++ b/spring-expression/src/main/java/org/springframework/expression/spel/ast/MethodReference.java @@ -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"); * 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); mv.visitMethodInsn((isStaticMethod ? INVOKESTATIC : (method.isDefault() ? INVOKEINTERFACE : INVOKEVIRTUAL)), - classDesc, method.getName(), - CodeFlow.createSignatureDescriptor(method), method.getDeclaringClass().isInterface()); + classDesc, method.getName(), CodeFlow.createSignatureDescriptor(method), + method.getDeclaringClass().isInterface()); cf.pushDescriptor(this.exitTypeDescriptor); if (this.originalPrimitiveExitTypeDescriptor != null) { diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java index 5576b595385..7c4fc536b63 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelCompilerTests.java @@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThat; */ class SpelCompilerTests { - @Test // gh-24357 + @Test // gh-24357 void expressionCompilesWhenMethodComesFromPublicInterface() { SpelParserConfiguration config = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, null); SpelExpressionParser parser = new SpelExpressionParser(config); @@ -50,6 +50,31 @@ class SpelCompilerTests { 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 { @@ -114,4 +139,40 @@ class SpelCompilerTests { 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(); + } + } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java index 4d9da27bb55..5c6c1d859d2 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/StatementCreatorUtils.java @@ -66,12 +66,11 @@ public abstract class StatementCreatorUtils { * completely, i.e. to never even attempt to retrieve {@link PreparedStatement#getParameterMetaData()} * for {@link StatementCreatorUtils#setNull} calls. *

The default is "false", trying {@code getParameterType} calls first and falling back to - * {@link PreparedStatement#setNull} / {@link PreparedStatement#setObject} calls based on well-known - * behavior of common databases. Spring records JDBC drivers with non-working {@code getParameterType} - * implementations and won't attempt to call that method for that driver again, always falling back. - *

Consider switching this flag to "true" if you experience misbehavior at runtime, e.g. with - * a connection pool setting back the {@link PreparedStatement} instance in case of an exception - * thrown from {@code getParameterType} (as reported on JBoss AS 7). + * {@link PreparedStatement#setNull} / {@link PreparedStatement#setObject} calls based on + * well-known behavior of common databases. + *

Consider switching this flag to "true" if you experience misbehavior at runtime, + * e.g. with connection pool issues in case of an exception thrown from {@code getParameterType} + * (as reported on JBoss AS 7) or in case of performance problems (as reported on PostgreSQL). */ 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") || jdbcDriverName.startsWith("jConnect") || - jdbcDriverName.startsWith("SQLServer")|| + jdbcDriverName.startsWith("SQLServer") || jdbcDriverName.startsWith("Apache Derby")) { sqlTypeToUse = Types.VARCHAR; } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java index ae80a8eb916..37505db2ef3 100755 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/metadata/CallMetaDataContext.java @@ -355,7 +355,7 @@ public class CallMetaDataContext { logger.debug("Using declared out parameter '" + paramName + "' for function return value"); } - setFunctionReturnName(paramName); + this.actualFunctionReturnName = paramName; returnDeclared = true; } } @@ -393,8 +393,8 @@ public class CallMetaDataContext { "Unable to locate declared parameter for function return value - " + " add an SqlOutParameter with name '" + getFunctionReturnName() + "'"); } - else if (paramName != null) { - setFunctionReturnName(paramName); + else { + this.actualFunctionReturnName = param.getName(); } } else { @@ -422,7 +422,7 @@ public class CallMetaDataContext { (StringUtils.hasLength(paramNameToUse) ? paramNameToUse : getFunctionReturnName()); workParams.add(provider.createDefaultOutParameter(returnNameToUse, meta)); if (isFunction()) { - setFunctionReturnName(returnNameToUse); + this.actualFunctionReturnName = returnNameToUse; outParamNames.add(returnNameToUse); } if (logger.isDebugEnabled()) { diff --git a/src/docs/asciidoc/data-access.adoc b/src/docs/asciidoc/data-access.adoc index 3e529a9df63..ef59c4225a8 100644 --- a/src/docs/asciidoc/data-access.adoc +++ b/src/docs/asciidoc/data-access.adoc @@ -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 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) -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, either through a 'BatchPreparedStatementSetter' (as shown earlier), through an explicit type