18
pom.xml
18
pom.xml
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -101,7 +102,9 @@
|
||||
<configuration>
|
||||
<artifacts>
|
||||
<artifact>
|
||||
<file>${project.build.directory}/${project.artifactId}-${project.version}.zip</file>
|
||||
<file>
|
||||
${project.build.directory}/${project.artifactId}-${project.version}.zip
|
||||
</file>
|
||||
<type>zip</type>
|
||||
</artifact>
|
||||
</artifacts>
|
||||
@@ -358,7 +361,10 @@
|
||||
<exclude>**/OpenJpa*</exclude>
|
||||
<exclude>**/EclipseLink*</exclude>
|
||||
</excludes>
|
||||
<argLine>-javaagent:${settings.localRepository}/org/springframework/spring-instrument/${spring}/spring-instrument-${spring}.jar -javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco}/org.jacoco.agent-${jacoco}-runtime.jar=destfile=${jacoco.destfile}</argLine>
|
||||
<argLine>
|
||||
-javaagent:${settings.localRepository}/org/springframework/spring-instrument/${spring}/spring-instrument-${spring}.jar
|
||||
-javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco}/org.jacoco.agent-${jacoco}-runtime.jar=destfile=${jacoco.destfile}
|
||||
</argLine>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
@@ -371,7 +377,11 @@
|
||||
<includes>
|
||||
<include>**/EclipseLink*Tests.java</include>
|
||||
</includes>
|
||||
<argLine>-javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco}/org.jacoco.agent-${jacoco}-runtime.jar=destfile=${jacoco.destfile} -javaagent:${settings.localRepository}/org/eclipse/persistence/org.eclipse.persistence.jpa/${eclipselink}/org.eclipse.persistence.jpa-${eclipselink}.jar -javaagent:${settings.localRepository}/org/springframework/spring-instrument/${spring}/spring-instrument-${spring}.jar</argLine>
|
||||
<argLine>
|
||||
-javaagent:${settings.localRepository}/org/jacoco/org.jacoco.agent/${jacoco}/org.jacoco.agent-${jacoco}-runtime.jar=destfile=${jacoco.destfile}
|
||||
-javaagent:${settings.localRepository}/org/eclipse/persistence/org.eclipse.persistence.jpa/${eclipselink}/org.eclipse.persistence.jpa-${eclipselink}.jar
|
||||
-javaagent:${settings.localRepository}/org/springframework/spring-instrument/${spring}/spring-instrument-${spring}.jar
|
||||
</argLine>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
@@ -54,6 +54,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Nicolas Cirigliano
|
||||
* @author Jens Schauder
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public abstract class JpaQueryExecution {
|
||||
|
||||
@@ -319,19 +320,16 @@ public abstract class JpaQueryExecution {
|
||||
boolean returnsResultSet = storedProcedure.execute();
|
||||
|
||||
if (returnsResultSet) {
|
||||
if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive())
|
||||
|
||||
if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive()) {
|
||||
throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION);
|
||||
|
||||
List<?> result = storedProcedure.getResultList();
|
||||
|
||||
if (!storedProcedureJpaQuery.getQueryMethod().isCollectionQuery()) {
|
||||
if (result.isEmpty())
|
||||
return null;
|
||||
if (result.size() == 1)
|
||||
return result.get(0);
|
||||
}
|
||||
|
||||
return result;
|
||||
if (storedProcedureJpaQuery.getQueryMethod().isCollectionQuery()) {
|
||||
return storedProcedure.getResultList();
|
||||
} else {
|
||||
return storedProcedure.getSingleResult();
|
||||
}
|
||||
}
|
||||
|
||||
return storedProcedureJpaQuery.extractOutputValue(storedProcedure);
|
||||
|
||||
@@ -54,7 +54,7 @@ public @interface Procedure {
|
||||
String outputParameterName() default "";
|
||||
|
||||
/**
|
||||
* Whether the procedure returns a Ref Cursor from the database {@code false}.
|
||||
* Whether the procedure returns a Ref Cursor from the database - defaults to {@code false}.
|
||||
*/
|
||||
boolean refCursor() default false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2020 the original author or authors.
|
||||
* Copyright 2021 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.
|
||||
@@ -16,23 +16,27 @@
|
||||
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.persistence.ParameterMode;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* This class represents a Stored Procedure Parameter
|
||||
* and an instance of the annotation {@link javax.persistence.StoredProcedureParameter}.
|
||||
* This class represents a Stored Procedure Parameter and an instance of the annotation
|
||||
* {@link javax.persistence.StoredProcedureParameter}.
|
||||
*
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class ProcedureParameter {
|
||||
class ProcedureParameter {
|
||||
|
||||
private final String name;
|
||||
private final ParameterMode mode;
|
||||
private final Class<?> type;
|
||||
|
||||
public ProcedureParameter(@Nullable String name, ParameterMode mode, Class<?> type) {
|
||||
ProcedureParameter(@Nullable String name, ParameterMode mode, Class<?> type) {
|
||||
|
||||
this.name = name;
|
||||
this.mode = mode;
|
||||
this.type = type;
|
||||
@@ -49,4 +53,29 @@ public class ProcedureParameter {
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(o instanceof ProcedureParameter)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProcedureParameter that = (ProcedureParameter) o;
|
||||
return Objects.equals(name, that.name) && mode == that.mode && Objects.equals(type, that.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, mode, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProcedureParameter{" + "name='" + name + '\'' + ", mode=" + mode + ", type=" + type + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,9 @@ package org.springframework.data.jpa.repository.query;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
@@ -28,6 +30,7 @@ import javax.persistence.StoredProcedureParameter;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -40,6 +43,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Diego Diez
|
||||
* @author Jeff Sheets
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
* @since 1.6
|
||||
*/
|
||||
enum StoredProcedureAttributeSource {
|
||||
@@ -69,9 +73,9 @@ enum StoredProcedureAttributeSource {
|
||||
}
|
||||
|
||||
String procedureName = deriveProcedureNameFrom(method, procedure);
|
||||
if (StringUtils.isEmpty(procedureName)) {
|
||||
throw new IllegalArgumentException("Could not determine name of procedure for @Procedure annotated method: "
|
||||
+ method);
|
||||
if (ObjectUtils.isEmpty(procedureName)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not determine name of procedure for @Procedure annotated method: " + method);
|
||||
}
|
||||
|
||||
return new StoredProcedureAttributes(procedureName, createOutputProcedureParameterFrom(method, procedure));
|
||||
@@ -96,42 +100,57 @@ enum StoredProcedureAttributeSource {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract procedure attributes from method and procedure.
|
||||
*
|
||||
* @param method
|
||||
* @param namedStoredProc
|
||||
* @param procedure
|
||||
* @return
|
||||
*/
|
||||
private StoredProcedureAttributes newProcedureAttributesFrom(Method method,
|
||||
NamedStoredProcedureQuery namedStoredProc, Procedure procedure) {
|
||||
private StoredProcedureAttributes newProcedureAttributesFrom(Method method, NamedStoredProcedureQuery namedStoredProc,
|
||||
Procedure procedure) {
|
||||
|
||||
List<ProcedureParameter> outputParameters = new ArrayList<>();
|
||||
List<ProcedureParameter> outputParameters;
|
||||
|
||||
if (!procedure.outputParameterName().isEmpty()) {
|
||||
|
||||
// we give the output parameter definition from the @Procedure annotation precedence
|
||||
outputParameters.add(createOutputProcedureParameterFrom(method, procedure));
|
||||
outputParameters = Collections.singletonList(createOutputProcedureParameterFrom(method, procedure));
|
||||
} else {
|
||||
|
||||
// try to discover the output parameter
|
||||
List<StoredProcedureParameter> namedProcedureOutputParameters = extractOutputParametersFrom(namedStoredProc);
|
||||
|
||||
for (StoredProcedureParameter outputParameter : namedProcedureOutputParameters) {
|
||||
outputParameters.add(new ProcedureParameter(
|
||||
outputParameter.name(), outputParameter.mode(), outputParameter.type()));
|
||||
}
|
||||
outputParameters = extractOutputParametersFrom(namedStoredProc).stream() //
|
||||
.map(namedParameter -> new ProcedureParameter(namedParameter.name(), namedParameter.mode(),
|
||||
namedParameter.type())) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return new StoredProcedureAttributes(namedStoredProc.name(), outputParameters, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ProcedureParameter} from relevant {@link Method} and {@link Procedure}.
|
||||
*
|
||||
* @param method
|
||||
* @param procedure
|
||||
* @return
|
||||
*/
|
||||
private ProcedureParameter createOutputProcedureParameterFrom(Method method, Procedure procedure) {
|
||||
|
||||
return new ProcedureParameter(procedure.outputParameterName(),
|
||||
procedure.refCursor() ? ParameterMode.REF_CURSOR : ParameterMode.OUT,
|
||||
method.getReturnType());
|
||||
procedure.refCursor() ? ParameterMode.REF_CURSOR : ParameterMode.OUT, method.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate all the {@Link NamedStoredProcedureQuery} parameters into a {@link List} of
|
||||
* {@link StoredProcedureParameter}s.
|
||||
*
|
||||
* @param namedStoredProc
|
||||
* @return
|
||||
*/
|
||||
private List<StoredProcedureParameter> extractOutputParametersFrom(NamedStoredProcedureQuery namedStoredProc) {
|
||||
|
||||
List<StoredProcedureParameter> outputParameters = new ArrayList<StoredProcedureParameter>();
|
||||
List<StoredProcedureParameter> outputParameters = new ArrayList<>();
|
||||
|
||||
for (StoredProcedureParameter param : namedStoredProc.parameters()) {
|
||||
|
||||
@@ -190,9 +209,12 @@ enum StoredProcedureAttributeSource {
|
||||
* @param procedure
|
||||
* @return
|
||||
*/
|
||||
private String derivedNamedProcedureNameFrom(Method method, JpaEntityMetadata<?> entityMetadata, Procedure procedure) {
|
||||
return StringUtils.hasText(procedure.name()) ? procedure.name() : entityMetadata.getEntityName() + "."
|
||||
+ method.getName();
|
||||
private String derivedNamedProcedureNameFrom(Method method, JpaEntityMetadata<?> entityMetadata,
|
||||
Procedure procedure) {
|
||||
|
||||
return StringUtils.hasText(procedure.name()) //
|
||||
? procedure.name() //
|
||||
: entityMetadata.getEntityName() + "." + method.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,7 +223,7 @@ enum StoredProcedureAttributeSource {
|
||||
*/
|
||||
private List<NamedStoredProcedureQuery> collectNamedStoredProcedureQueriesFrom(Class<?> entityType) {
|
||||
|
||||
List<NamedStoredProcedureQuery> queries = new ArrayList<NamedStoredProcedureQuery>();
|
||||
List<NamedStoredProcedureQuery> queries = new ArrayList<>();
|
||||
|
||||
NamedStoredProcedureQueries namedQueriesAnnotation = AnnotatedElementUtils.findMergedAnnotation(entityType,
|
||||
NamedStoredProcedureQueries.class);
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Stored procedure configuration for JPA 2.1 {@link StoredProcedureQuery}s.
|
||||
*
|
||||
@@ -48,7 +48,7 @@ class StoredProcedureAttributes {
|
||||
/**
|
||||
* Creates a new {@link StoredProcedureAttributes}.
|
||||
*
|
||||
* @param procedureName must not be {@literal null}.
|
||||
* @param procedureName must not be {@literal null}.
|
||||
*/
|
||||
StoredProcedureAttributes(String procedureName, ProcedureParameter parameter) {
|
||||
this(procedureName, Collections.singletonList(parameter), false);
|
||||
@@ -57,14 +57,16 @@ class StoredProcedureAttributes {
|
||||
/**
|
||||
* Creates a new {@link StoredProcedureAttributes}.
|
||||
*
|
||||
* @param procedureName must not be {@literal null}.
|
||||
* @param procedureName must not be {@literal null}.
|
||||
* @param namedStoredProcedure flag signaling if the stored procedure has a name.
|
||||
*/
|
||||
StoredProcedureAttributes(String procedureName, List<ProcedureParameter> outputProcedureParameters, boolean namedStoredProcedure) {
|
||||
StoredProcedureAttributes(String procedureName, List<ProcedureParameter> outputProcedureParameters,
|
||||
boolean namedStoredProcedure) {
|
||||
|
||||
Assert.notNull(procedureName, "ProcedureName must not be null!");
|
||||
Assert.notNull(outputProcedureParameters, "OutputProcedureParameters must not be null!");
|
||||
Assert.isTrue(outputProcedureParameters.size() != 1 || outputProcedureParameters.get(0) != null, "ProcedureParameters must not have size 1 with a null value");
|
||||
Assert.isTrue(outputProcedureParameters.size() != 1 || outputProcedureParameters.get(0) != null,
|
||||
"ProcedureParameters must not have size 1 with a null value");
|
||||
|
||||
this.procedureName = procedureName;
|
||||
this.namedStoredProcedure = namedStoredProcedure;
|
||||
@@ -77,15 +79,16 @@ class StoredProcedureAttributes {
|
||||
}
|
||||
|
||||
private List<ProcedureParameter> getParametersWithCompletedNames(List<ProcedureParameter> procedureParameters) {
|
||||
return IntStream.range(0, procedureParameters.size())
|
||||
.mapToObj(i -> getParameterWithCompletedName(procedureParameters.get(i), i))
|
||||
|
||||
return IntStream.range(0, procedureParameters.size()) //
|
||||
.mapToObj(i -> getParameterWithCompletedName(procedureParameters.get(i), i)) //
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ProcedureParameter getParameterWithCompletedName(ProcedureParameter parameter, int i) {
|
||||
return new ProcedureParameter(
|
||||
completeOutputParameterName(i, parameter.getName()),
|
||||
parameter.getMode(), parameter.getType());
|
||||
|
||||
return new ProcedureParameter(completeOutputParameterName(i, parameter.getName()), parameter.getMode(),
|
||||
parameter.getType());
|
||||
}
|
||||
|
||||
private String completeOutputParameterName(int i, String paramName) {
|
||||
@@ -130,6 +133,7 @@ class StoredProcedureAttributes {
|
||||
* @return
|
||||
*/
|
||||
public boolean hasReturnValue() {
|
||||
|
||||
if (getOutputProcedureParameters().isEmpty())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -18,20 +18,16 @@ package org.springframework.data.jpa.repository.query;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
|
||||
import org.springframework.data.repository.query.Parameter;
|
||||
import org.springframework.data.repository.query.ParametersParameterAccessor;
|
||||
import org.springframework.data.repository.query.QueryMethod;
|
||||
import org.springframework.data.repository.query.ResultProcessor;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -143,7 +139,8 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
|
||||
|
||||
for (int i = 0; i < outputParameters.size(); i++) {
|
||||
ProcedureParameter outputParameter = outputParameters.get(i);
|
||||
outputValues.put(outputParameter.getName(), extractOutputParameterValue(outputParameter, i, storedProcedureQuery));
|
||||
outputValues.put(outputParameter.getName(),
|
||||
extractOutputParameterValue(outputParameter, i, storedProcedureQuery));
|
||||
}
|
||||
|
||||
return outputValues;
|
||||
@@ -152,12 +149,13 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
|
||||
/**
|
||||
* @return The value of an output parameter either by name or by index.
|
||||
*/
|
||||
private Object extractOutputParameterValue(ProcedureParameter outputParameter, Integer index, StoredProcedureQuery storedProcedureQuery) {
|
||||
private Object extractOutputParameterValue(ProcedureParameter outputParameter, Integer index,
|
||||
StoredProcedureQuery storedProcedureQuery) {
|
||||
|
||||
JpaParameters methodParameters = getQueryMethod().getParameters();
|
||||
|
||||
return useNamedParameters && StringUtils.hasText(outputParameter.getName()) ?
|
||||
storedProcedureQuery.getOutputParameterValue(outputParameter.getName())
|
||||
return useNamedParameters && StringUtils.hasText(outputParameter.getName())
|
||||
? storedProcedureQuery.getOutputParameterValue(outputParameter.getName())
|
||||
: storedProcedureQuery.getOutputParameterValue(methodParameters.getNumberOfParameters() + index + 1);
|
||||
}
|
||||
|
||||
@@ -166,7 +164,8 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
|
||||
*/
|
||||
private StoredProcedureQuery createStoredProcedure() {
|
||||
|
||||
return procedureAttributes.isNamedStoredProcedure() ? newNamedStoredProcedureQuery()
|
||||
return procedureAttributes.isNamedStoredProcedure() //
|
||||
? newNamedStoredProcedureQuery()
|
||||
: newAdhocStoredProcedureQuery();
|
||||
}
|
||||
|
||||
@@ -205,15 +204,20 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
|
||||
|
||||
ProcedureParameter procedureOutput = procedureAttributes.getOutputProcedureParameters().get(0);
|
||||
|
||||
/* If the stored procedure returns a ResultSet without using REF_CURSOR,
|
||||
it is not necessary to declare an output parameter */
|
||||
if ((isResultSetProcedure() && procedureOutput.getMode() == ParameterMode.REF_CURSOR) || !isResultSetProcedure()) {
|
||||
/**
|
||||
* If there is a {@link java.sql.ResultSet} with a {@link ParameterMode#REF_CURSOR}, find the output parameter.
|
||||
* Otherwise, no need, there is no need to find an output parameter.
|
||||
*/
|
||||
if (storedProcedureHasResultSetUsingRefCursor(procedureOutput) || !isResultSetProcedure()) {
|
||||
|
||||
if (useNamedParameters) {
|
||||
procedureQuery.registerStoredProcedureParameter(procedureOutput.getName(), procedureOutput.getType(), procedureOutput.getMode());
|
||||
procedureQuery.registerStoredProcedureParameter(procedureOutput.getName(), procedureOutput.getType(),
|
||||
procedureOutput.getMode());
|
||||
} else {
|
||||
|
||||
// Output parameter should be after the input parameters
|
||||
int outputParameterIndex = params.getNumberOfParameters() + 1;
|
||||
|
||||
procedureQuery.registerStoredProcedureParameter(outputParameterIndex, procedureOutput.getType(),
|
||||
procedureOutput.getMode());
|
||||
}
|
||||
@@ -223,18 +227,29 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
|
||||
return procedureQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does this stored procedure has a {@link java.sql.ResultSet} using {@link ParameterMode#REF_CURSOR}?
|
||||
*
|
||||
* @param procedureOutput
|
||||
* @return
|
||||
*/
|
||||
private boolean storedProcedureHasResultSetUsingRefCursor(ProcedureParameter procedureOutput) {
|
||||
return isResultSetProcedure() && procedureOutput.getMode() == ParameterMode.REF_CURSOR;
|
||||
}
|
||||
|
||||
private StoredProcedureQuery createAdhocStoredProcedureQuery() {
|
||||
String procedureName = procedureAttributes.getProcedureName();
|
||||
|
||||
if (getQueryMethod().isQueryForEntity()) {
|
||||
return getEntityManager().createStoredProcedureQuery(procedureName,
|
||||
|
||||
return getEntityManager().createStoredProcedureQuery(procedureAttributes.getProcedureName(),
|
||||
getQueryMethod().getEntityInformation().getJavaType());
|
||||
}
|
||||
|
||||
return getEntityManager().createStoredProcedureQuery(procedureName);
|
||||
return getEntityManager().createStoredProcedureQuery(procedureAttributes.getProcedureName());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return true if the stored procedure will use a ResultSet to return data and not output parameters
|
||||
*/
|
||||
private boolean isResultSetProcedure() {
|
||||
|
||||
@@ -69,6 +69,8 @@ import com.querydsl.core.types.EntityPath;
|
||||
* @author Jens Schauder
|
||||
* @author Stefan Fussenegger
|
||||
* @author Réda Housni Alaoui
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
*/
|
||||
public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
|
||||
@@ -214,6 +216,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
||||
@Override
|
||||
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
|
||||
QueryMethodEvaluationContextProvider evaluationContextProvider) {
|
||||
|
||||
return Optional.of(JpaQueryLookupStrategy.create(entityManager, queryMethodFactory, key, evaluationContextProvider,
|
||||
escapeCharacter));
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.ComponentScan.Filter;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Jeff Sheets
|
||||
* @author Jens Schauder
|
||||
* @author Gabriel Basilio
|
||||
* @author Greg Turnquist
|
||||
* @since 1.6
|
||||
*/
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -72,7 +73,9 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
void shouldCreateStoredProcedureAttributesFromProcedureMethodWithImplicitProcedureName() {
|
||||
|
||||
StoredProcedureAttributes attr = creator.createFrom(method("plus1inout", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -86,6 +89,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -99,6 +103,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -112,6 +117,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("explicitPlus1inoutViaProcedureNameAlias", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -125,6 +131,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
method("explicitPlus1inoutViaProcedureNameAliasAndOutputParameterName", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -138,6 +145,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("entityAnnotatedCustomNamedProcedurePlus1IO", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("User.plus1IO");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -151,6 +159,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("entityAnnotatedCustomNamedProcedureOutputParamNamePlus1IO", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("User.plus1IO");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -183,6 +192,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
StoredProcedureAttributes attr = creator.createFrom(method("plus1", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("User.plus1");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -196,6 +206,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("plus1inoutWithComposedAnnotationOverridingProcedureName", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("plus1inout");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -209,6 +220,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("plus1inoutWithComposedAnnotationOverridingName", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("User.plus1");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Integer.class);
|
||||
@@ -222,6 +234,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("0_input_1_row_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Dummy.class);
|
||||
@@ -235,6 +248,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("1_input_1_row_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(Dummy.class);
|
||||
@@ -247,6 +261,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
StoredProcedureAttributes attr = creator.createFrom(method("entityListFromResultSetWithNoInput"), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("0_input_1_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(List.class);
|
||||
@@ -261,6 +276,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("1_input_1_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(List.class);
|
||||
@@ -274,6 +290,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("genericObjectListFromResultSetWithInput", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("1_input_1_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(List.class);
|
||||
@@ -287,6 +304,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("entityListFromResultSetWithInputAndNamedOutput", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("1_input_1_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.OUT);
|
||||
assertThat(outputParameter.getType()).isEqualTo(List.class);
|
||||
@@ -300,6 +318,7 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
.createFrom(method("entityListFromResultSetWithInputAndNamedOutputAndCursor", Integer.class), entityMetadata);
|
||||
|
||||
ProcedureParameter outputParameter = attr.getOutputProcedureParameters().get(0);
|
||||
|
||||
assertThat(attr.getProcedureName()).isEqualTo("1_input_1_resultset");
|
||||
assertThat(outputParameter.getMode()).isEqualTo(ParameterMode.REF_CURSOR);
|
||||
assertThat(outputParameter.getType()).isEqualTo(List.class);
|
||||
@@ -319,58 +338,50 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
/**
|
||||
* Explicitly mapped to a procedure with name "plus1inout" in database.
|
||||
*/
|
||||
@Procedure("plus1inout")
|
||||
// DATAJPA-455
|
||||
@Procedure("plus1inout") // DATAJPA-455
|
||||
Integer explicitlyNamedPlus1inout(Integer arg);
|
||||
|
||||
/**
|
||||
* Explicitly mapped to a procedure with name "plus1inout" in database via alias.
|
||||
*/
|
||||
@Procedure(procedureName = "plus1inout")
|
||||
// DATAJPA-455
|
||||
@Procedure(procedureName = "plus1inout") // DATAJPA-455
|
||||
Integer explicitPlus1inoutViaProcedureNameAlias(Integer arg);
|
||||
|
||||
/**
|
||||
* Explicitly mapped to a procedure with name "plus1inout" in database via alias and explicitly named ouput
|
||||
* Explicitly mapped to a procedure with name "plus1inout" in database via alias and explicitly named output
|
||||
* parameter.
|
||||
*/
|
||||
@Procedure(procedureName = "plus1inout", outputParameterName = "res")
|
||||
// DATAJPA-1297
|
||||
@Procedure(procedureName = "plus1inout", outputParameterName = "res") // DATAJPA-1297
|
||||
Integer explicitPlus1inoutViaProcedureNameAliasAndOutputParameterName(Integer arg);
|
||||
|
||||
/**
|
||||
* Implicitly mapped to a procedure with name "plus1inout" in database via alias.
|
||||
*/
|
||||
@Procedure
|
||||
// DATAJPA-455
|
||||
@Procedure // DATAJPA-455
|
||||
Integer plus1inout(Integer arg);
|
||||
|
||||
/**
|
||||
* Explicitly mapped to named stored procedure "User.plus1IO" in {@link EntityManager}.
|
||||
*/
|
||||
@Procedure(name = "User.plus1IO")
|
||||
// DATAJPA-455
|
||||
@Procedure(name = "User.plus1IO") // DATAJPA-455
|
||||
Integer entityAnnotatedCustomNamedProcedurePlus1IO(@Param("arg") Integer arg);
|
||||
|
||||
/**
|
||||
* Explicitly mapped to named stored procedure "User.plus1IO" in {@link EntityManager}. With a outputParameterName
|
||||
* Explicitly mapped to named stored procedure "User.plus1IO" in {@link EntityManager} with an outputParameterName.
|
||||
*/
|
||||
@Procedure(name = "User.plus1IO", outputParameterName = "override")
|
||||
// DATAJPA-707
|
||||
@Procedure(name = "User.plus1IO", outputParameterName = "override") // DATAJPA-707
|
||||
Integer entityAnnotatedCustomNamedProcedureOutputParamNamePlus1IO(@Param("arg") Integer arg);
|
||||
|
||||
/**
|
||||
* Explicitly mapped to named stored procedure "User.plus1IO2" in {@link EntityManager}.
|
||||
*/
|
||||
@Procedure(name = "User.plus1IO2")
|
||||
// DATAJPA-707
|
||||
@Procedure(name = "User.plus1IO2") // DATAJPA-707
|
||||
Map<String, Integer> entityAnnotatedCustomNamedProcedurePlus1IO2(@Param("arg") Integer arg);
|
||||
|
||||
/**
|
||||
* Implicitly mapped to named stored procedure "User.plus1" in {@link EntityManager}.
|
||||
*/
|
||||
@Procedure
|
||||
// DATAJPA-455
|
||||
@Procedure // DATAJPA-455
|
||||
Integer plus1(@Param("arg") Integer arg);
|
||||
|
||||
@ComposedProcedureUsingAliasFor(explicitProcedureName = "plus1inout")
|
||||
@@ -379,32 +390,25 @@ class StoredProcedureAttributeSourceUnitTests {
|
||||
@ComposedProcedureUsingAliasFor(emProcedureName = "User.plus1")
|
||||
Integer plus1inoutWithComposedAnnotationOverridingName(Integer arg);
|
||||
|
||||
@Procedure("0_input_1_row_resultset")
|
||||
// DATAJPA-1657
|
||||
@Procedure("0_input_1_row_resultset") // DATAJPA-1657
|
||||
Dummy singleEntityFrom1RowResultSetAndNoInput();
|
||||
|
||||
@Procedure("1_input_1_row_resultset")
|
||||
// DATAJPA-1657
|
||||
@Procedure("1_input_1_row_resultset") // DATAJPA-1657
|
||||
Dummy singleEntityFrom1RowResultSetWithInput(Integer arg);
|
||||
|
||||
@Procedure("0_input_1_resultset")
|
||||
// DATAJPA-1657
|
||||
@Procedure("0_input_1_resultset") // DATAJPA-1657
|
||||
List<Dummy> entityListFromResultSetWithNoInput();
|
||||
|
||||
@Procedure("1_input_1_resultset")
|
||||
// DATAJPA-1657
|
||||
@Procedure("1_input_1_resultset") // DATAJPA-1657
|
||||
List<Dummy> entityListFromResultSetWithInput(Integer arg);
|
||||
|
||||
@Procedure("1_input_1_resultset")
|
||||
// DATAJPA-1657
|
||||
@Procedure("1_input_1_resultset") // DATAJPA-1657
|
||||
List<Object[]> genericObjectListFromResultSetWithInput(Integer arg);
|
||||
|
||||
@Procedure(value = "1_input_1_resultset", outputParameterName = "dummies")
|
||||
// DATAJPA-1657
|
||||
@Procedure(value = "1_input_1_resultset", outputParameterName = "dummies") // DATAJPA-1657
|
||||
List<Dummy> entityListFromResultSetWithInputAndNamedOutput(Integer arg);
|
||||
|
||||
@Procedure(value = "1_input_1_resultset", outputParameterName = "dummies", refCursor = true)
|
||||
// DATAJPA-1657
|
||||
@Procedure(value = "1_input_1_resultset", outputParameterName = "dummies", refCursor = true) // DATAJPA-1657
|
||||
List<Dummy> entityListFromResultSetWithInputAndNamedOutputAndCursor(Integer arg);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,10 @@ package org.springframework.data.jpa.repository.query;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.springframework.data.jpa.repository.query.StoredProcedureAttributes.*;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import javax.persistence.ParameterMode;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link StoredProcedureAttributes}.
|
||||
*
|
||||
@@ -33,8 +33,8 @@ class StoredProcedureAttributesUnitTests {
|
||||
@Test // DATAJPA-681
|
||||
void usesSyntheticOutputParameterNameForAdhocProcedureWithoutOutputName() {
|
||||
|
||||
ProcedureParameter outputParameter = new ProcedureParameter(null, ParameterMode.OUT, Long.class);
|
||||
StoredProcedureAttributes attributes = new StoredProcedureAttributes("procedure", outputParameter);
|
||||
StoredProcedureAttributes attributes = new StoredProcedureAttributes("procedure",
|
||||
new ProcedureParameter(null, ParameterMode.OUT, Long.class));
|
||||
assertThat(attributes.getOutputProcedureParameters().get(0).getName()).isEqualTo(SYNTHETIC_OUTPUT_PARAMETER_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user