Allow parameter name binding for SimpleJdbcCall

Update SimpleJdbcCall to offer a way to use named parameters binding
instead of the simple `?` binding it offers thus far.

Issue: SPR-12801
This commit is contained in:
Stephane Nicoll 2015-05-13 08:56:32 +02:00
parent 477d4c5126
commit 8dec8823fb
5 changed files with 99 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -46,6 +46,7 @@ import org.springframework.util.StringUtils;
*
* @author Thomas Risberg
* @author Juergen Hoeller
* @author Kiril Nugmanov
* @since 2.5
*/
public class CallMetaDataContext {
@ -83,6 +84,9 @@ public class CallMetaDataContext {
/** Should we access call parameter meta data info or not */
private boolean accessCallParameterMetaData = true;
/** Should we bind parameter by name **/
private boolean namedBinding;
/** The provider of call meta data */
private CallMetaDataProvider metaDataProvider;
@ -213,6 +217,19 @@ public class CallMetaDataContext {
return this.accessCallParameterMetaData;
}
/**
* Specify whether parameters should be bound by name.
*/
public void setNamedBinding(boolean namedBinding) {
this.namedBinding = namedBinding;
}
/**
* Check whether parameters should be bound by name.
*/
public boolean isNamedBinding() {
return namedBinding;
}
/**
* Create a ReturnResultSetParameter/SqlOutParameter depending on the support provided
@ -595,7 +612,7 @@ public class CallMetaDataContext {
callString += ", ";
}
if (parameterCount >= 0) {
callString += "?";
callString += createParameterBinding(parameter);
}
parameterCount++;
}
@ -605,4 +622,17 @@ public class CallMetaDataContext {
return callString;
}
/**
* Build the parameter binding fragment.
* @param parameter call parameter
* @return parameter binding fragment
*/
protected String createParameterBinding(SqlParameter parameter) {
if (isNamedBinding()) {
return parameter.getName() + " => ?";
} else {
return "?";
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -198,6 +198,21 @@ public abstract class AbstractJdbcCall {
this.callMetaDataContext.setAccessCallParameterMetaData(accessCallParameterMetaData);
}
/**
* Does parameters should be bound by name?
*/
public boolean isNamedBinding() {
return this.callMetaDataContext.isNamedBinding();
}
/**
* Specify whether parameters should be bound by name.
* The default is {@code false}.
*/
public void setNamedBinding(boolean namedBinding) {
this.callMetaDataContext.setNamedBinding(namedBinding);
}
/**
* Get the call string that should be used based on parameters and meta data.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -53,6 +53,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
* to provide the ability to chain multiple ones together in a "fluent" interface style.
*
* @author Thomas Risberg
* @author Stephane Nicoll
* @since 2.5
* @see java.sql.DatabaseMetaData
* @see org.springframework.jdbc.core.JdbcTemplate
@ -139,6 +140,12 @@ public class SimpleJdbcCall extends AbstractJdbcCall implements SimpleJdbcCallOp
return this;
}
@Override
public SimpleJdbcCall withNamedBinding() {
setNamedBinding(true);
return this;
}
@Override
@SuppressWarnings("unchecked")
public <T> T executeFunction(Class<T> returnType, Object... args) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2014 the original author or authors.
* Copyright 2002-2015 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.
@ -28,6 +28,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
* as it can easily be mocked or stubbed.
*
* @author Thomas Risberg
* @author Stephane Nicoll
* @since 2.5
*/
public interface SimpleJdbcCallOperations {
@ -100,6 +101,12 @@ public interface SimpleJdbcCallOperations {
*/
SimpleJdbcCallOperations withoutProcedureColumnMetaDataAccess();
/**
* Indicates that parameters should be bound by name.
* @return the instance of this SimpleJdbcCall
*/
SimpleJdbcCallOperations withNamedBinding();
/**
* Execute the stored function and return the results obtained as an Object of the

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
@ -24,6 +24,7 @@ import java.sql.SQLException;
import java.sql.Types;
import javax.sql.DataSource;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@ -41,9 +42,10 @@ import static org.mockito.BDDMockito.*;
import static org.springframework.tests.Matchers.*;
/**
* Mock object based tests for SimpleJdbcCall.
* Tests for {@link SimpleJdbcCall}.
*
* @author Thomas Risberg
* @author Kiril Nugmanov
*/
public class SimpleJdbcCallTests {
@ -193,7 +195,8 @@ public class SimpleJdbcCallTests {
}
@Test public void testAddInvoiceFuncWithMetaDataUsingArrayParams() throws Exception {
@Test
public void testAddInvoiceFuncWithMetaDataUsingArrayParams() throws Exception {
initializeAddInvoiceWithMetaData(true);
SimpleJdbcCall adder = new SimpleJdbcCall(dataSource).withFunctionName("add_invoice");
Number newId = adder.executeFunction(Number.class, 1103, 3);
@ -203,6 +206,34 @@ public class SimpleJdbcCallTests {
}
@Test
public void testCorrectFunctionStatement() throws Exception {
initializeAddInvoiceWithMetaData(true);
SimpleJdbcCall adder = new SimpleJdbcCall(dataSource).withFunctionName("add_invoice");
adder.compile();
verifyStatement(adder, "{? = call ADD_INVOICE(?, ?)}");
}
@Test
public void testCorrectFunctionStatementNamed() throws Exception {
initializeAddInvoiceWithMetaData(true);
SimpleJdbcCall adder = new SimpleJdbcCall(dataSource).withNamedBinding().withFunctionName("add_invoice");
adder.compile();
verifyStatement(adder, "{? = call ADD_INVOICE(AMOUNT => ?, CUSTID => ?)}");
}
@Test
public void testCorrectProcedureStatementNamed() throws Exception {
initializeAddInvoiceWithMetaData(false);
SimpleJdbcCall adder = new SimpleJdbcCall(dataSource).withNamedBinding().withProcedureName("add_invoice");
adder.compile();
verifyStatement(adder, "{call ADD_INVOICE(AMOUNT => ?, CUSTID => ?, NEWID => ?)}");
}
private void verifyStatement(SimpleJdbcCall adder, String expected) {
Assert.assertEquals("Incorrect call statement", expected, adder.getCallString());
}
private void initializeAddInvoiceWithoutMetaData(boolean isFunction)
throws SQLException {
given(databaseMetaData.getDatabaseProductName()).willReturn("MyDB");
@ -281,6 +312,5 @@ public class SimpleJdbcCallTests {
verify(callableStatement).close();
verify(proceduresResultSet).close();
verify(procedureColumnsResultSet).close();
}
}
}