Browse Source

Polish Javadoc and internals of R2DBC support

pull/35405/head
Sam Brannen 7 months ago
parent
commit
de97e35189
  1. 75
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/NamedParameterUtils.java
  2. 9
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/AnonymousBindMarkers.java
  3. 11
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java
  4. 8
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarkers.java
  5. 32
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarkersFactoryResolver.java
  6. 15
      spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/IndexedBindMarkers.java
  7. 164
      spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsTests.java

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 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.
@ -513,14 +513,50 @@ abstract class NamedParameterUtils {
private final BindParameterSource parameterSource; private final BindParameterSource parameterSource;
ExpandedQuery(String expandedSql, NamedParameters parameters, BindParameterSource parameterSource) { ExpandedQuery(String expandedSql, NamedParameters parameters, BindParameterSource parameterSource) {
this.expandedSql = expandedSql; this.expandedSql = expandedSql;
this.parameters = parameters; this.parameters = parameters;
this.parameterSource = parameterSource; this.parameterSource = parameterSource;
} }
@Override
public String toQuery() {
return this.expandedSql;
}
@Override
public String getSource() {
return this.expandedSql;
}
@Override
public void bindTo(BindTarget target) {
for (String namedParameter : this.parameterSource.getParameterNames()) {
Parameter parameter = this.parameterSource.getValue(namedParameter);
if (parameter.getValue() == null) {
bindNull(target, namedParameter, parameter);
}
else {
bind(target, namedParameter, parameter);
}
}
}
private void bindNull(BindTarget target, String identifier, Parameter parameter) {
List<BindMarker> bindMarkers = getBindMarkers(identifier);
if (bindMarkers == null) {
target.bind(identifier, parameter);
return;
}
for (BindMarker bindMarker : bindMarkers) {
bindMarker.bind(target, parameter);
}
}
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
public void bind(BindTarget target, String identifier, Parameter parameter) { private void bind(BindTarget target, String identifier, Parameter parameter) {
List<BindMarker> bindMarkers = getBindMarkers(identifier); List<BindMarker> bindMarkers = getBindMarkers(identifier);
if (bindMarkers == null) { if (bindMarkers == null) {
target.bind(identifier, parameter); target.bind(identifier, parameter);
@ -555,19 +591,8 @@ abstract class NamedParameterUtils {
markers.next().bind(target, valueToBind); markers.next().bind(target, valueToBind);
} }
public void bindNull(BindTarget target, String identifier, Parameter parameter) {
List<BindMarker> bindMarkers = getBindMarkers(identifier);
if (bindMarkers == null) {
target.bind(identifier, parameter);
return;
}
for (BindMarker bindMarker : bindMarkers) {
bindMarker.bind(target, parameter);
}
}
@Nullable @Nullable
List<BindMarker> getBindMarkers(String identifier) { private List<BindMarker> getBindMarkers(String identifier) {
List<NamedParameters.NamedParameter> parameters = this.parameters.getMarker(identifier); List<NamedParameters.NamedParameter> parameters = this.parameters.getMarker(identifier);
if (parameters == null) { if (parameters == null) {
return null; return null;
@ -579,28 +604,6 @@ abstract class NamedParameterUtils {
return markers; return markers;
} }
@Override
public String getSource() {
return this.expandedSql;
}
@Override
public void bindTo(BindTarget target) {
for (String namedParameter : this.parameterSource.getParameterNames()) {
Parameter parameter = this.parameterSource.getValue(namedParameter);
if (parameter.getValue() == null) {
bindNull(target, namedParameter, parameter);
}
else {
bind(target, namedParameter, parameter);
}
}
}
@Override
public String toQuery() {
return this.expandedSql;
}
} }
} }

9
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/AnonymousBindMarkers.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2025 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.
@ -19,8 +19,9 @@ package org.springframework.r2dbc.core.binding;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/** /**
* Anonymous, index-based bind marker using a static placeholder. * Anonymous, index-based bind markers that use a static placeholder.
* Instances are bound by the ordinal position ordered by the appearance of *
* <p>Instances are bound by the ordinal position ordered by the appearance of
* the placeholder. This implementation creates indexed bind markers using * the placeholder. This implementation creates indexed bind markers using
* an anonymous placeholder that correlates with an index. * an anonymous placeholder that correlates with an index.
* *
@ -46,7 +47,7 @@ class AnonymousBindMarkers implements BindMarkers {
/** /**
* Create a new {@link AnonymousBindMarkers} instance given {@code placeholder}. * Create a new {@link AnonymousBindMarkers} instance for the given {@code placeholder}.
* @param placeholder parameter bind marker * @param placeholder parameter bind marker
*/ */
AnonymousBindMarkers(String placeholder) { AnonymousBindMarkers(String placeholder) {

11
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarker.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2025 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.
@ -20,7 +20,8 @@ import io.r2dbc.spi.Statement;
/** /**
* A bind marker represents a single bindable parameter within a query. * A bind marker represents a single bindable parameter within a query.
* Bind markers are dialect-specific and provide a *
* <p>Bind markers are dialect-specific and provide a
* {@link #getPlaceholder() placeholder} that is used in the actual query. * {@link #getPlaceholder() placeholder} that is used in the actual query.
* *
* @author Mark Paluch * @author Mark Paluch
@ -37,7 +38,8 @@ public interface BindMarker {
String getPlaceholder(); String getPlaceholder();
/** /**
* Bind the given {@code value} to the {@link Statement} using the underlying binding strategy. * Bind the given {@code value} to the {@link Statement} using the underlying
* binding strategy.
* @param bindTarget the target to bind the value to * @param bindTarget the target to bind the value to
* @param value the actual value (must not be {@code null}; * @param value the actual value (must not be {@code null};
* use {@link #bindNull(BindTarget, Class)} for {@code null} values) * use {@link #bindNull(BindTarget, Class)} for {@code null} values)
@ -46,7 +48,8 @@ public interface BindMarker {
void bind(BindTarget bindTarget, Object value); void bind(BindTarget bindTarget, Object value);
/** /**
* Bind a {@code null} value to the {@link Statement} using the underlying binding strategy. * Bind a {@code null} value to the {@link Statement} using the underlying
* binding strategy.
* @param bindTarget the target to bind the value to * @param bindTarget the target to bind the value to
* @param valueType the value type (must not be {@code null}) * @param valueType the value type (must not be {@code null})
* @see Statement#bindNull * @see Statement#bindNull

8
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarkers.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2025 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.
@ -20,10 +20,10 @@ package org.springframework.r2dbc.core.binding;
* Bind markers represent placeholders in SQL queries for substitution * Bind markers represent placeholders in SQL queries for substitution
* for an actual parameter. Using bind markers allows creating safe queries * for an actual parameter. Using bind markers allows creating safe queries
* so query strings are not required to contain escaped values but rather * so query strings are not required to contain escaped values but rather
* the driver encodes parameter in the appropriate representation. * the driver encodes the parameter in the appropriate representation.
* *
* <p>{@link BindMarkers} is stateful and can be only used for a single binding * <p>{@link BindMarkers} is stateful and can be only used for a single binding
* pass of one or more parameters. It maintains bind indexes/bind parameter names. * pass of one or more parameters. It maintains bind indexes or bind parameter names.
* *
* @author Mark Paluch * @author Mark Paluch
* @since 5.3 * @since 5.3
@ -41,7 +41,7 @@ public interface BindMarkers {
/** /**
* Create a new {@link BindMarker} that accepts a {@code hint}. * Create a new {@link BindMarker} that accepts a {@code hint}.
* Implementations are allowed to consider/ignore/filter * <p>Implementations are allowed to consider/ignore/filter
* the name hint to create more expressive bind markers. * the name hint to create more expressive bind markers.
* @param hint an optional name hint that can be used as part of the bind marker * @param hint an optional name hint that can be used as part of the bind marker
* @return a new {@link BindMarker} * @return a new {@link BindMarker}

32
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/BindMarkersFactoryResolver.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2024 the original author or authors. * Copyright 2002-2025 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.
@ -30,8 +30,8 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
/** /**
* Resolves a {@link BindMarkersFactory} from a {@link ConnectionFactory} using * Resolves a {@link BindMarkersFactory} from a {@link ConnectionFactory} using
* {@link BindMarkerFactoryProvider}. Dialect resolution uses Spring's * a {@link BindMarkerFactoryProvider}. Dialect resolution uses Spring's
* {@link SpringFactoriesLoader spring.factories} to determine available extensions. * {@link SpringFactoriesLoader spring.factories} file to determine available extensions.
* *
* @author Mark Paluch * @author Mark Paluch
* @since 5.3 * @since 5.3
@ -45,8 +45,8 @@ public final class BindMarkersFactoryResolver {
/** /**
* Retrieve a {@link BindMarkersFactory} by inspecting {@link ConnectionFactory} * Retrieve a {@link BindMarkersFactory} by inspecting the supplied
* and its metadata. * {@link ConnectionFactory} and its metadata.
* @param connectionFactory the connection factory to inspect * @param connectionFactory the connection factory to inspect
* @return the resolved {@link BindMarkersFactory} * @return the resolved {@link BindMarkersFactory}
* @throws NoBindMarkersFactoryException if no {@link BindMarkersFactory} can be resolved * @throws NoBindMarkersFactoryException if no {@link BindMarkersFactory} can be resolved
@ -69,18 +69,21 @@ public final class BindMarkersFactoryResolver {
/** /**
* SPI to extend Spring's default R2DBC BindMarkersFactory discovery mechanism. * SPI to extend Spring's default R2DBC {@link BindMarkersFactory} discovery
* Implementations of this interface are discovered through Spring's * mechanism.
*
* <p>Implementations of this interface are discovered through Spring's
* {@link SpringFactoriesLoader} mechanism. * {@link SpringFactoriesLoader} mechanism.
*
* @see SpringFactoriesLoader * @see SpringFactoriesLoader
*/ */
@FunctionalInterface @FunctionalInterface
public interface BindMarkerFactoryProvider { public interface BindMarkerFactoryProvider {
/** /**
* Return a {@link BindMarkersFactory} for a {@link ConnectionFactory}. * Return a {@link BindMarkersFactory} for the given {@link ConnectionFactory}.
* @param connectionFactory the connection factory to be used with the {@link BindMarkersFactory} * @param connectionFactory the connection factory to be used with the {@code BindMarkersFactory}
* @return the {@link BindMarkersFactory} if the {@link BindMarkerFactoryProvider} * @return the {@code BindMarkersFactory} if this {@code BindMarkerFactoryProvider}
* can provide a bind marker factory object, otherwise {@code null} * can provide a bind marker factory object, otherwise {@code null}
*/ */
@Nullable @Nullable
@ -89,7 +92,7 @@ public final class BindMarkersFactoryResolver {
/** /**
* Exception thrown when {@link BindMarkersFactoryResolver} cannot resolve a * Exception thrown when a {@link BindMarkersFactoryResolver} cannot resolve a
* {@link BindMarkersFactory}. * {@link BindMarkersFactory}.
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
@ -106,8 +109,11 @@ public final class BindMarkersFactoryResolver {
/** /**
* Built-in bind maker factories. Used typically as last {@link BindMarkerFactoryProvider} * Built-in bind marker factories.
* when other providers register with a higher precedence. *
* <p>Typically used as the last {@link BindMarkerFactoryProvider} when other
* providers are registered with a higher precedence.
*
* @see org.springframework.core.Ordered * @see org.springframework.core.Ordered
* @see org.springframework.core.annotation.AnnotationAwareOrderComparator * @see org.springframework.core.annotation.AnnotationAwareOrderComparator
*/ */

15
spring-r2dbc/src/main/java/org/springframework/r2dbc/core/binding/IndexedBindMarkers.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2025 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.
@ -19,7 +19,7 @@ package org.springframework.r2dbc.core.binding;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
/** /**
* Index-based bind marker. This implementation creates indexed bind * Index-based bind markers. This implementation creates indexed bind
* markers using a numeric index and an optional prefix for bind markers * markers using a numeric index and an optional prefix for bind markers
* to be represented within the query string. * to be represented within the query string.
* *
@ -43,14 +43,15 @@ class IndexedBindMarkers implements BindMarkers {
/** /**
* Create a new {@link IndexedBindMarker} instance given {@code prefix} and {@code beginWith}. * Create a new {@link IndexedBindMarker} instance for the given {@code prefix}
* @param prefix bind parameter prefix * and {@code beginWith} value.
* @param beginWith the first index to use * @param prefix the bind parameter prefix
* @param beginIndex the first index to use
*/ */
IndexedBindMarkers(String prefix, int beginWith) { IndexedBindMarkers(String prefix, int beginIndex) {
this.counter = 0; this.counter = 0;
this.prefix = prefix; this.prefix = prefix;
this.offset = beginWith; this.offset = beginIndex;
} }

164
spring-r2dbc/src/test/java/org/springframework/r2dbc/core/NamedParameterUtilsTests.java

@ -28,8 +28,6 @@ import org.junit.jupiter.params.provider.ValueSource;
import org.springframework.r2dbc.core.binding.BindMarkersFactory; import org.springframework.r2dbc.core.binding.BindMarkersFactory;
import org.springframework.r2dbc.core.binding.BindTarget; import org.springframework.r2dbc.core.binding.BindTarget;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -320,34 +318,17 @@ class NamedParameterUtilsTests {
assertThat(operation.toQuery()) assertThat(operation.toQuery())
.isEqualTo("SELECT * FROM person where name = $1 or lastname = $1"); .isEqualTo("SELECT * FROM person where name = $1 or lastname = $1");
Map<Integer, Object> bindings = new HashMap<>(); TrackingBindTarget trackingBindTarget = new TrackingBindTarget();
operation.bindTo(new BindTarget() { operation.bindTo(trackingBindTarget);
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
bindings.put(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
});
assertThat(bindings) assertThat(trackingBindTarget.bindings)
.hasSize(1) .hasSize(1)
.containsEntry(0, Parameters.in("foo")); .containsEntry(0, Parameters.in("foo"));
} }
@Test @Test
void multipleEqualCollectionParameterReferencesForIndexedMarkersBindsValueOnce() { void multipleEqualCollectionParameterReferencesForIndexedMarkersBindsValuesOnce() {
String sql = "SELECT * FROM person where name IN (:ids) or lastname IN (:ids)"; String sql = "SELECT * FROM person where name IN (:ids) or lastname IN (:ids)";
MapBindParameterSource source = new MapBindParameterSource(Map.of("ids", MapBindParameterSource source = new MapBindParameterSource(Map.of("ids",
@ -357,71 +338,40 @@ class NamedParameterUtilsTests {
assertThat(operation.toQuery()) assertThat(operation.toQuery())
.isEqualTo("SELECT * FROM person where name IN ($1, $2, $3) or lastname IN ($1, $2, $3)"); .isEqualTo("SELECT * FROM person where name IN ($1, $2, $3) or lastname IN ($1, $2, $3)");
MultiValueMap<Integer, Object> bindings = new LinkedMultiValueMap<>(); TrackingBindTarget trackingBindTarget = new TrackingBindTarget();
operation.bindTo(new BindTarget() { operation.bindTo(trackingBindTarget);
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
bindings.add(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
});
assertThat(bindings) assertThat(trackingBindTarget.bindings)
.hasSize(3) .hasSize(3)
.containsEntry(0, List.of("foo")) .containsEntry(0, "foo")
.containsEntry(1, List.of("bar")) .containsEntry(1, "bar")
.containsEntry(2, List.of("baz")); .containsEntry(2, "baz");
} }
@Test // gh-34768 @Test // gh-34768
@Disabled("Disabled until gh-34768 is addressed") @Disabled("Disabled until gh-34768 is addressed")
void multipleEqualCollectionParameterReferencesForAnonymousMarkersBindsValueTwice() { void multipleEqualCollectionParameterReferencesForAnonymousMarkersBindsValuesTwice() {
String sql = "SELECT * FROM fund_info WHERE fund_code IN (:fundCodes) OR fund_code IN (:fundCodes)"; String sql = "SELECT * FROM fund_info WHERE fund_code IN (:fundCodes) OR fund_code IN (:fundCodes)";
MapBindParameterSource source = new MapBindParameterSource(Map.of("fundCodes", Parameters.in(List.of("foo")))); MapBindParameterSource source = new MapBindParameterSource(Map.of("fundCodes", Parameters.in(List.of("foo", "bar", "baz"))));
PreparedOperation<String> operation = NamedParameterUtils.substituteNamedParameters(sql, ANONYMOUS_MARKERS, source); PreparedOperation<String> operation = NamedParameterUtils.substituteNamedParameters(sql, ANONYMOUS_MARKERS, source);
assertThat(operation.toQuery()) assertThat(operation.toQuery())
.isEqualTo("SELECT * FROM fund_info WHERE fund_code IN (?) OR fund_code IN (?)"); .isEqualTo("SELECT * FROM fund_info WHERE fund_code IN (?, ?, ?) OR fund_code IN (?, ?, ?)");
Map<Integer, Object> bindings = new HashMap<>();
operation.bindTo(new BindTarget() {
@Override
public void bind(String identifier, Object value) {}
@Override
public void bind(int index, Object value) {
bindings.put(index, value);
}
@Override TrackingBindTarget trackingBindTarget = new TrackingBindTarget();
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override operation.bindTo(trackingBindTarget);
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
});
assertThat(bindings) assertThat(trackingBindTarget.bindings)
.hasSize(2) .hasSize(6)
.containsEntry(0, "foo") .containsEntry(0, "foo")
.containsEntry(1, "foo"); .containsEntry(1, "bar")
.containsEntry(2, "baz")
.containsEntry(3, "foo")
.containsEntry(4, "bar")
.containsEntry(5, "baz");
} }
@Test @Test
@ -434,28 +384,11 @@ class NamedParameterUtilsTests {
assertThat(operation.toQuery()) assertThat(operation.toQuery())
.isEqualTo("SELECT * FROM person where name = ? or lastname = ?"); .isEqualTo("SELECT * FROM person where name = ? or lastname = ?");
Map<Integer, Object> bindings = new HashMap<>(); TrackingBindTarget trackingBindTarget = new TrackingBindTarget();
operation.bindTo(new BindTarget() { operation.bindTo(trackingBindTarget);
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
bindings.put(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
});
assertThat(bindings) assertThat(trackingBindTarget.bindings)
.hasSize(2) .hasSize(2)
.containsEntry(0, Parameters.in("foo")) .containsEntry(0, Parameters.in("foo"))
.containsEntry(1, Parameters.in("foo")); .containsEntry(1, Parameters.in("foo"));
@ -471,28 +404,11 @@ class NamedParameterUtilsTests {
assertThat(operation.toQuery()) assertThat(operation.toQuery())
.isEqualTo("SELECT * FROM person where name = $1 or lastname = $1"); .isEqualTo("SELECT * FROM person where name = $1 or lastname = $1");
Map<Integer, Object> bindings = new HashMap<>(); TrackingBindTarget trackingBindTarget = new TrackingBindTarget();
operation.bindTo(new BindTarget() { operation.bindTo(trackingBindTarget);
@Override
public void bind(String identifier, Object value) {
throw new UnsupportedOperationException();
}
@Override
public void bind(int index, Object value) {
bindings.put(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
});
assertThat(bindings) assertThat(trackingBindTarget.bindings)
.hasSize(1) .hasSize(1)
.containsEntry(0, Parameters.in(String.class)); .containsEntry(0, Parameters.in(String.class));
} }
@ -508,4 +424,28 @@ class NamedParameterUtilsTests {
new MapBindParameterSource()).toQuery(); new MapBindParameterSource()).toQuery();
} }
private static class TrackingBindTarget implements BindTarget {
final Map<Integer, Object> bindings = new HashMap<>();
@Override
public void bind(String identifier, Object value) {}
@Override
public void bind(int index, Object value) {
this.bindings.put(index, value);
}
@Override
public void bindNull(String identifier, Class<?> type) {
throw new UnsupportedOperationException();
}
@Override
public void bindNull(int index, Class<?> type) {
throw new UnsupportedOperationException();
}
}
} }

Loading…
Cancel
Save