org.springframework.data.jpa.repository.query.StoredProcedureAttributeSource Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-data-jpa Show documentation
Show all versions of spring-data-jpa Show documentation
Spring Data module for JPA repositories.
/*
* Copyright 2014-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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository.query;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.persistence.NamedStoredProcedureQueries;
import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.StoredProcedureParameter;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A factory class for {@link StoredProcedureAttributes}.
*
* @author Thomas Darimont
* @author Oliver Gierke
* @since 1.6
*/
enum StoredProcedureAttributeSource {
INSTANCE;
/**
* Creates a new {@link StoredProcedureAttributes} from the given {@link Method} and {@link JpaEntityMetadata}.
*
* @param method must not be {@literal null}
* @param entityMetadata must not be {@literal null}
* @return
*/
public StoredProcedureAttributes createFrom(Method method, JpaEntityMetadata entityMetadata) {
Assert.notNull(method, "Method must not be null!");
Assert.notNull(entityMetadata, "EntityMetadata must not be null!");
Procedure procedure = method.getAnnotation(Procedure.class);
Assert.notNull(procedure, "Method must have an @Procedure annotation!");
NamedStoredProcedureQuery namedStoredProc = tryFindAnnotatedNamedStoredProcedureQuery(method, entityMetadata,
procedure);
if (namedStoredProc != null) {
return newProcedureAttributesFrom(method, namedStoredProc, procedure);
}
String procedureName = deriveProcedureNameFrom(method, procedure);
if (StringUtils.isEmpty(procedureName)) {
throw new IllegalArgumentException("Could not determine name of procedure for @Procedure annotated method: "
+ method);
}
return new StoredProcedureAttributes(procedureName, null, method.getReturnType(), false);
}
/**
* Tries to derive the procedure name from the given {@link Procedure}, falls back to the name of the given
* {@link Method}.
*
* @param method
* @param procedure
* @return
*/
private String deriveProcedureNameFrom(Method method, Procedure procedure) {
if (StringUtils.hasText(procedure.value())) {
return procedure.value();
}
String procedureName = procedure.procedureName();
return StringUtils.hasText(procedureName) ? procedureName : method.getName();
}
/**
* @param method
* @param namedStoredProc
* @param procedure
* @return
*/
private StoredProcedureAttributes newProcedureAttributesFrom(Method method,
NamedStoredProcedureQuery namedStoredProc, Procedure procedure) {
String outputParameterName = null;
Class outputParameterType = null;
if (!procedure.outputParameterName().isEmpty()) {
// we give the output parameter definition from the @Procedure annotation precedence
outputParameterName = procedure.outputParameterName();
} else {
// try to discover the output parameter
List outputParameters = extractOutputParametersFrom(namedStoredProc);
if (outputParameters.size() != 1 && !void.class.equals(method.getReturnType())) {
throw new IllegalStateException(String.format(
"Could not create ProcedureAttributes from %s. We currently support exactly one output parameter!", method));
}
if (!outputParameters.isEmpty()) {
StoredProcedureParameter outputParameter = outputParameters.get(0);
outputParameterName = outputParameter.name();
outputParameterType = outputParameter.type();
}
}
if (outputParameterType == null || Object.class.equals(outputParameterType)
|| void.class.equals(outputParameterType)) {
outputParameterType = method.getReturnType();
}
return new StoredProcedureAttributes(namedStoredProc.name(), outputParameterName, outputParameterType, true);
}
private List extractOutputParametersFrom(NamedStoredProcedureQuery namedStoredProc) {
List outputParameters = new ArrayList();
for (StoredProcedureParameter param : namedStoredProc.parameters()) {
switch (param.mode()) {
case OUT:
case INOUT:
case REF_CURSOR:
outputParameters.add(param);
break;
case IN:
default:
continue;
}
}
return outputParameters;
}
/**
* @param method must not be {@literal null}.
* @param entityMetadata must not be {@literal null}.
* @param procedure must not be {@literal null}.
* @return
*/
private NamedStoredProcedureQuery tryFindAnnotatedNamedStoredProcedureQuery(Method method,
JpaEntityMetadata entityMetadata, Procedure procedure) {
Assert.notNull(method, "Method must not be null!");
Assert.notNull(entityMetadata, "EntityMetadata must not be null!");
Assert.notNull(procedure, "Procedure must not be null!");
Class entityType = entityMetadata.getJavaType();
List queries = collectNamedStoredProcedureQueriesFrom(entityType);
if (queries.isEmpty()) {
return null;
}
String namedProcedureName = derivedNamedProcedureNameFrom(method, entityMetadata, procedure);
for (NamedStoredProcedureQuery query : queries) {
if (query.name().equals(namedProcedureName)) {
return query;
}
}
return null;
}
/**
* @param method
* @param entityMetadata
* @param procedure
* @return
*/
private String derivedNamedProcedureNameFrom(Method method, JpaEntityMetadata entityMetadata, Procedure procedure) {
return StringUtils.hasText(procedure.name()) ? procedure.name() : entityMetadata.getEntityName() + "."
+ method.getName();
}
/**
* @param entityType
* @return
*/
private List collectNamedStoredProcedureQueriesFrom(Class entityType) {
List queries = new ArrayList();
NamedStoredProcedureQueries namedQueriesAnnotation = entityType.getAnnotation(NamedStoredProcedureQueries.class);
if (namedQueriesAnnotation != null) {
queries.addAll(Arrays.asList(namedQueriesAnnotation.value()));
}
NamedStoredProcedureQuery namedQueryAnnotation = entityType.getAnnotation(NamedStoredProcedureQuery.class);
if (namedQueryAnnotation != null) {
queries.add(namedQueryAnnotation);
}
return queries;
}
}