DATAJPA-871 - Allow usage of composed annotations using @AliasFor.
We allow and support composing annotations for: @Entity, @EntityGraph, @Lock, @Modifying, @Query, @QueryHints as well as @Procedure. Original pull request: #166.
This commit is contained in:
committed by
Oliver Gierke
parent
154e3370cf
commit
a1509f9517
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.jpa.repository.query.JpaQueryMethod;
|
||||
*
|
||||
* Since 1.9 we support the definition of dynamic {@link EntityGraph}s by allowing to customize the fetch-graph via
|
||||
* via {@link #attributePaths()} ad-hoc fetch-graph configuration.
|
||||
* @author Christoph Strobl
|
||||
*
|
||||
* If {@link #attributePaths()} are specified then we ignore the entity-graph name {@link #value()}
|
||||
* and treat this {@link EntityGraph} as dynamic.
|
||||
@@ -38,7 +39,7 @@ import org.springframework.data.jpa.repository.query.JpaQueryMethod;
|
||||
* @since 1.6
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Documented
|
||||
public @interface EntityGraph {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2015 the original author or authors.
|
||||
* Copyright 2008-2016 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.
|
||||
@@ -25,9 +25,10 @@ import java.lang.annotation.Target;
|
||||
* Indicates a method should be regarded as modifying query.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Documented
|
||||
public @interface Modifying {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 the original author or authors.
|
||||
* Copyright 2008-2016 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,9 +28,10 @@ import org.springframework.data.annotation.QueryAnnotation;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@QueryAnnotation
|
||||
@Documented
|
||||
public @interface Query {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -24,6 +25,7 @@ import org.springframework.util.StringUtils;
|
||||
* Default implementation for {@link JpaEntityMetadata}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class DefaultJpaEntityMetadata<T> implements JpaEntityMetadata<T> {
|
||||
|
||||
@@ -55,7 +57,7 @@ public class DefaultJpaEntityMetadata<T> implements JpaEntityMetadata<T> {
|
||||
*/
|
||||
public String getEntityName() {
|
||||
|
||||
Entity entity = domainType.getAnnotation(Entity.class);
|
||||
Entity entity = AnnotatedElementUtils.findMergedAnnotation(domainType, Entity.class);
|
||||
boolean hasName = null != entity && StringUtils.hasText(entity.name());
|
||||
|
||||
return hasName ? entity.name() : domainType.getSimpleName();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2015 the original author or authors.
|
||||
* Copyright 2008-2016 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.
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import static org.springframework.core.annotation.AnnotationUtils.*;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -28,6 +27,7 @@ import java.util.Set;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.QueryHint;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.jpa.provider.QueryExtractor;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
@@ -48,6 +48,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class JpaQueryMethod extends QueryMethod {
|
||||
|
||||
@@ -135,7 +136,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
@Override
|
||||
public boolean isModifyingQuery() {
|
||||
|
||||
return null != method.getAnnotation(Modifying.class);
|
||||
return null != AnnotationUtils.findAnnotation(method, Modifying.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +148,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
|
||||
List<QueryHint> result = new ArrayList<QueryHint>();
|
||||
|
||||
QueryHints hints = getAnnotation(method, QueryHints.class);
|
||||
QueryHints hints = AnnotatedElementUtils.findMergedAnnotation(method, QueryHints.class);
|
||||
if (hints != null) {
|
||||
result.addAll(Arrays.asList(hints.value()));
|
||||
}
|
||||
@@ -162,7 +163,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
*/
|
||||
LockModeType getLockModeType() {
|
||||
|
||||
Lock annotation = findAnnotation(method, Lock.class);
|
||||
Lock annotation = AnnotatedElementUtils.findMergedAnnotation(method, Lock.class);
|
||||
return (LockModeType) AnnotationUtils.getValue(annotation);
|
||||
}
|
||||
|
||||
@@ -174,7 +175,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
*/
|
||||
JpaEntityGraph getEntityGraph() {
|
||||
|
||||
EntityGraph annotation = findAnnotation(method, EntityGraph.class);
|
||||
EntityGraph annotation = AnnotatedElementUtils.findMergedAnnotation(method, EntityGraph.class);
|
||||
return annotation == null ? null : new JpaEntityGraph(annotation, getNamedQueryName());
|
||||
}
|
||||
|
||||
@@ -186,7 +187,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
*/
|
||||
boolean applyHintsToCountQuery() {
|
||||
|
||||
QueryHints hints = getAnnotation(method, QueryHints.class);
|
||||
QueryHints hints = AnnotatedElementUtils.findMergedAnnotation(method, QueryHints.class);
|
||||
return hints != null ? hints.forCounting() : false;
|
||||
}
|
||||
|
||||
@@ -284,8 +285,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
* @return
|
||||
*/
|
||||
boolean getClearAutomatically() {
|
||||
|
||||
return (Boolean) AnnotationUtils.getValue(method.getAnnotation(Modifying.class), "clearAutomatically");
|
||||
return getMergedOrDefaultAnnotationValue("clearAutomatically", Modifying.class, Boolean.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,12 +298,18 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
* @return
|
||||
*/
|
||||
private <T> T getAnnotationValue(String attribute, Class<T> type) {
|
||||
return getMergedOrDefaultAnnotationValue(attribute, Query.class, type);
|
||||
}
|
||||
|
||||
Query annotation = method.getAnnotation(Query.class);
|
||||
Object value = annotation == null ? AnnotationUtils.getDefaultValue(Query.class, attribute)
|
||||
: AnnotationUtils.getValue(annotation, attribute);
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private <T> T getMergedOrDefaultAnnotationValue(String attribute, Class annotationType, Class<T> targetType) {
|
||||
|
||||
return type.cast(value);
|
||||
Annotation annotation = AnnotatedElementUtils.findMergedAnnotation(method, annotationType);
|
||||
if (annotation == null) {
|
||||
return targetType.cast(AnnotationUtils.getDefaultValue(annotationType, attribute));
|
||||
}
|
||||
|
||||
return targetType.cast(AnnotationUtils.getValue(annotation, attribute));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -339,7 +345,7 @@ public class JpaQueryMethod extends QueryMethod {
|
||||
* @return
|
||||
*/
|
||||
public boolean isProcedureQuery() {
|
||||
return method.getAnnotation(Procedure.class) != null;
|
||||
return AnnotationUtils.findAnnotation(method, Procedure.class) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -25,9 +25,10 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Procedure {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
* Copyright 2014-2016 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 javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -32,6 +33,7 @@ import org.springframework.util.StringUtils;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
enum StoredProcedureAttributeSource {
|
||||
@@ -50,7 +52,7 @@ enum StoredProcedureAttributeSource {
|
||||
Assert.notNull(method, "Method must not be null!");
|
||||
Assert.notNull(entityMetadata, "EntityMetadata must not be null!");
|
||||
|
||||
Procedure procedure = method.getAnnotation(Procedure.class);
|
||||
Procedure procedure = AnnotatedElementUtils.findMergedAnnotation(method, Procedure.class);
|
||||
Assert.notNull(procedure, "Method must have an @Procedure annotation!");
|
||||
|
||||
NamedStoredProcedureQuery namedStoredProc = tryFindAnnotatedNamedStoredProcedureQuery(method, entityMetadata,
|
||||
@@ -201,12 +203,14 @@ enum StoredProcedureAttributeSource {
|
||||
|
||||
List<NamedStoredProcedureQuery> queries = new ArrayList<NamedStoredProcedureQuery>();
|
||||
|
||||
NamedStoredProcedureQueries namedQueriesAnnotation = entityType.getAnnotation(NamedStoredProcedureQueries.class);
|
||||
NamedStoredProcedureQueries namedQueriesAnnotation = AnnotatedElementUtils.findMergedAnnotation(entityType,
|
||||
NamedStoredProcedureQueries.class);
|
||||
if (namedQueriesAnnotation != null) {
|
||||
queries.addAll(Arrays.asList(namedQueriesAnnotation.value()));
|
||||
}
|
||||
|
||||
NamedStoredProcedureQuery namedQueryAnnotation = entityType.getAnnotation(NamedStoredProcedureQuery.class);
|
||||
NamedStoredProcedureQuery namedQueryAnnotation = AnnotatedElementUtils.findMergedAnnotation(entityType,
|
||||
NamedStoredProcedureQuery.class);
|
||||
if (namedQueryAnnotation != null) {
|
||||
queries.add(namedQueryAnnotation);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2011-2015 the original author or authors.
|
||||
* Copyright 2011-2016 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.aop.TargetSource;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.interceptor.ExposeInvocationInterceptor;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.data.jpa.repository.EntityGraph;
|
||||
import org.springframework.data.jpa.repository.Lock;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.util.ClassUtils;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, BeanClassLoaderAware {
|
||||
|
||||
@@ -164,19 +166,19 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
|
||||
}
|
||||
|
||||
private static EntityGraph findEntityGraph(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, EntityGraph.class);
|
||||
return AnnotatedElementUtils.findMergedAnnotation(method, EntityGraph.class);
|
||||
}
|
||||
|
||||
private static LockModeType findLockModeType(Method method) {
|
||||
|
||||
Lock annotation = AnnotationUtils.findAnnotation(method, Lock.class);
|
||||
Lock annotation = AnnotatedElementUtils.findMergedAnnotation(method, Lock.class);
|
||||
return annotation == null ? null : (LockModeType) AnnotationUtils.getValue(annotation);
|
||||
}
|
||||
|
||||
private static Map<String, Object> findQueryHints(Method method) {
|
||||
|
||||
Map<String, Object> queryHints = new HashMap<String, Object>();
|
||||
QueryHints queryHintsAnnotation = AnnotationUtils.findAnnotation(method, QueryHints.class);
|
||||
QueryHints queryHintsAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, QueryHints.class);
|
||||
|
||||
if (queryHintsAnnotation != null) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2011 the original author or authors.
|
||||
* Copyright 2008-2016 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.
|
||||
@@ -33,6 +33,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -59,6 +60,7 @@ import org.springframework.data.repository.query.QueryMethod;
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class JpaQueryMethodUnitTests {
|
||||
@@ -393,6 +395,148 @@ public class JpaQueryMethodUnitTests {
|
||||
getQueryMethod(ValidRepository.class, "queryWithPositionalBinding", String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForLockLockMode() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getLockModeType(), is(LockModeType.PESSIMISTIC_FORCE_INCREMENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryHints() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getHints(), hasSize(1));
|
||||
assertThat(method.getHints().get(0).name(), is("foo"));
|
||||
assertThat(method.getHints().get(0).value(), is("bar"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryHintsCounting() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.applyHintsToCountQuery(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForModifyingClearAutomatically() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.isModifyingQuery(), is(true));
|
||||
assertThat(method.getClearAutomatically(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForHintsApplyToCountQuery() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.applyHintsToCountQuery(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryValue() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getAnnotatedQuery(), is(equalTo("select u from User u where u.firstname = ?1")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryCountQuery() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getCountQuery(), is(equalTo("select u from User u where u.lastname = ?1")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryCountQueryProjection() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getCountQueryProjection(), is(equalTo("foo-bar")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryNamedQueryName() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getNamedQueryName(), is(equalTo("namedQueryName")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryNamedCountQueryName() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.getNamedCountQueryName(), is(equalTo("namedCountQueryName")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForQueryNativeQuery() throws Exception {
|
||||
|
||||
JpaQueryMethod method = getQueryMethod(ValidRepository.class, "withMetaAnnotationUsingAliasFor");
|
||||
|
||||
assertThat(method.isNativeQuery(), is(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void usesAliasedValueForEntityGraph() throws Exception {
|
||||
|
||||
doReturn(User.class).when(metadata).getDomainType();
|
||||
doReturn(User.class).when(metadata).getReturnedDomainClass((Method) any());
|
||||
|
||||
JpaQueryMethod method = new JpaQueryMethod(
|
||||
JpaRepositoryOverride.class.getMethod("getOneWithCustomEntityGraphAnnotation"), metadata, factory, extractor);
|
||||
|
||||
assertThat(method.getEntityGraph(), is(notNullValue()));
|
||||
assertThat(method.getEntityGraph().getName(), is("User.detail"));
|
||||
assertThat(method.getEntityGraph().getType(), is(EntityGraphType.LOAD));
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to define invalid repository methods for testing.
|
||||
*
|
||||
@@ -456,6 +600,9 @@ public class JpaQueryMethodUnitTests {
|
||||
|
||||
@Query("select u from User u where u.firstname = ?1")
|
||||
User queryWithPositionalBinding(@Param("firstname") String firstname);
|
||||
|
||||
@CustomComposedAnnotationWithAliasFor
|
||||
void withMetaAnnotationUsingAliasFor();
|
||||
}
|
||||
|
||||
static interface JpaRepositoryOverride extends JpaRepository<User, Long> {
|
||||
@@ -478,6 +625,10 @@ public class JpaQueryMethodUnitTests {
|
||||
*/
|
||||
@EntityGraph
|
||||
User getOneById(Long id);
|
||||
|
||||
@CustomComposedEntityGraphAnnotationWithAliasFor
|
||||
User getOneWithCustomEntityGraphAnnotation();
|
||||
|
||||
}
|
||||
|
||||
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
|
||||
@@ -486,4 +637,57 @@ public class JpaQueryMethodUnitTests {
|
||||
static @interface CustomAnnotation {
|
||||
|
||||
}
|
||||
|
||||
@Modifying
|
||||
@Query
|
||||
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
|
||||
@QueryHints(@QueryHint(name = "foo", value = "bar"))
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface CustomComposedAnnotationWithAliasFor {
|
||||
|
||||
@AliasFor(annotation = Modifying.class, attribute = "clearAutomatically")
|
||||
boolean doClear() default true;
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "value")
|
||||
String querystring() default "select u from User u where u.firstname = ?1";
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "countQuery")
|
||||
String countQueryString() default "select u from User u where u.lastname = ?1";
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "countProjection")
|
||||
String countProjectionString() default "foo-bar";
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "nativeQuery")
|
||||
boolean isNativeQuery() default true;
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "name")
|
||||
String namedQueryName() default "namedQueryName";
|
||||
|
||||
@AliasFor(annotation = Query.class, attribute = "countName")
|
||||
String namedCountQueryName() default "namedCountQueryName";
|
||||
|
||||
@AliasFor(annotation = Lock.class, attribute = "value")
|
||||
LockModeType lock() default LockModeType.PESSIMISTIC_FORCE_INCREMENT;
|
||||
|
||||
@AliasFor(annotation = QueryHints.class, attribute = "value")
|
||||
QueryHint[] hints() default @QueryHint(name = "foo", value = "bar")
|
||||
;
|
||||
|
||||
@AliasFor(annotation = QueryHints.class, attribute = "forCounting")
|
||||
boolean doCount() default true;
|
||||
}
|
||||
|
||||
@EntityGraph
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface CustomComposedEntityGraphAnnotationWithAliasFor {
|
||||
|
||||
@AliasFor(annotation = EntityGraph.class, attribute = "value")
|
||||
String graphName() default "User.detail";
|
||||
|
||||
@AliasFor(annotation = EntityGraph.class, attribute = "type")
|
||||
EntityGraphType graphType() default EntityGraphType.LOAD;
|
||||
|
||||
@AliasFor(annotation = EntityGraph.class, attribute = "attributePaths")
|
||||
String[] paths() default { "foo", "bar" };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2016 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.
|
||||
@@ -20,6 +20,8 @@ import static org.hamcrest.object.IsCompatibleType.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
@@ -29,6 +31,7 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.jpa.domain.sample.User;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
@@ -38,6 +41,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
* @author Thomas Darimont
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @since 1.6
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -102,8 +106,8 @@ public class StoredProcedureAttributeSourceUnitTests {
|
||||
@Test
|
||||
public void shouldCreateStoredProcedureAttributesFromProcedureMethodWithExplictProcedureNameAlias() {
|
||||
|
||||
StoredProcedureAttributes attr = creator.createFrom(
|
||||
method("explicitPlus1inoutViaProcedureNameAlias", Integer.class), entityMetadata);
|
||||
StoredProcedureAttributes attr = creator
|
||||
.createFrom(method("explicitPlus1inoutViaProcedureNameAlias", Integer.class), entityMetadata);
|
||||
|
||||
assertThat(attr.getProcedureName(), is("plus1inout"));
|
||||
assertThat(attr.getOutputParameterType(), is(typeCompatibleWith(Integer.class)));
|
||||
@@ -116,8 +120,8 @@ public class StoredProcedureAttributeSourceUnitTests {
|
||||
@Test
|
||||
public void shouldCreateStoredProcedureAttributesFromProcedureMethodBackedWithExplicitlyNamedProcedure() {
|
||||
|
||||
StoredProcedureAttributes attr = creator.createFrom(
|
||||
method("entityAnnotatedCustomNamedProcedurePlus1IO", Integer.class), entityMetadata);
|
||||
StoredProcedureAttributes attr = creator
|
||||
.createFrom(method("entityAnnotatedCustomNamedProcedurePlus1IO", Integer.class), entityMetadata);
|
||||
|
||||
assertThat(attr.getProcedureName(), is("User.plus1IO"));
|
||||
assertThat(attr.getOutputParameterType(), is(typeCompatibleWith(Integer.class)));
|
||||
@@ -137,6 +141,34 @@ public class StoredProcedureAttributeSourceUnitTests {
|
||||
assertThat(attr.getOutputParameterName(), is("res"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void aliasedStoredProcedure() {
|
||||
|
||||
StoredProcedureAttributes attr = creator
|
||||
.createFrom(method("plus1inoutWithComposedAnnotationOverridingProcedureName", Integer.class), entityMetadata);
|
||||
|
||||
assertThat(attr.getProcedureName(), is(equalTo("plus1inout")));
|
||||
assertThat(attr.getOutputParameterType(), is(typeCompatibleWith(Integer.class)));
|
||||
assertThat(attr.getOutputParameterName(), is(StoredProcedureAttributes.SYNTHETIC_OUTPUT_PARAMETER_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void aliasedStoredProcedure2() {
|
||||
|
||||
StoredProcedureAttributes attr = creator
|
||||
.createFrom(method("plus1inoutWithComposedAnnotationOverridingName", Integer.class), entityMetadata);
|
||||
|
||||
assertThat(attr.getProcedureName(), is(equalTo("User.plus1")));
|
||||
assertThat(attr.getOutputParameterType(), is(typeCompatibleWith(Integer.class)));
|
||||
assertThat(attr.getOutputParameterName(), is(equalTo("res")));
|
||||
}
|
||||
|
||||
private static Method method(String name, Class<?>... paramTypes) {
|
||||
return ReflectionUtils.findMethod(DummyRepository.class, name, paramTypes);
|
||||
}
|
||||
@@ -185,5 +217,28 @@ public class StoredProcedureAttributeSourceUnitTests {
|
||||
*/
|
||||
@Procedure
|
||||
Integer plus1(@Param("arg") Integer arg);
|
||||
|
||||
@ComposedProcedureUsingAliasFor(explicitProcedureName = "plus1inout")
|
||||
Integer plus1inoutWithComposedAnnotationOverridingProcedureName(Integer arg);
|
||||
|
||||
@ComposedProcedureUsingAliasFor(emProcedureName = "User.plus1")
|
||||
Integer plus1inoutWithComposedAnnotationOverridingName(Integer arg);
|
||||
}
|
||||
|
||||
@Procedure
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface ComposedProcedureUsingAliasFor {
|
||||
|
||||
@AliasFor(annotation = Procedure.class, attribute = "value")
|
||||
String dbProcedureName() default "";
|
||||
|
||||
@AliasFor(annotation = Procedure.class, attribute = "procedureName")
|
||||
String explicitProcedureName() default "";
|
||||
|
||||
@AliasFor(annotation = Procedure.class, attribute = "name")
|
||||
String emProcedureName() default "";
|
||||
|
||||
@AliasFor(annotation = Procedure.class, attribute = "outputParameterName")
|
||||
String outParamName() default "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2016 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.
|
||||
@@ -18,15 +18,20 @@ package org.springframework.data.jpa.repository.support;
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.jpa.repository.query.DefaultJpaEntityMetadata;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultJpaEntityMetadata}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
public class DefaultJpaEntityMetadataUnitTest {
|
||||
|
||||
@@ -57,8 +62,30 @@ public class DefaultJpaEntityMetadataUnitTest {
|
||||
assertThat(metadata.getEntityName(), is("Entity"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-871
|
||||
*/
|
||||
@Test
|
||||
public void returnsCustomizedEntityNameIfConfiguredViaComposedAnnotation() {
|
||||
|
||||
DefaultJpaEntityMetadata<BarWithComposedAnnotation> metadata = new DefaultJpaEntityMetadata<BarWithComposedAnnotation>(
|
||||
BarWithComposedAnnotation.class);
|
||||
assertThat(metadata.getEntityName(), is("Entity"));
|
||||
}
|
||||
|
||||
static class Foo {}
|
||||
|
||||
@Entity(name = "Entity")
|
||||
static class Bar {}
|
||||
|
||||
@CustomEntityAnnotationUsingAliasFor(entityName = "Entity")
|
||||
static class BarWithComposedAnnotation {}
|
||||
|
||||
@Entity
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
static @interface CustomEntityAnnotationUsingAliasFor {
|
||||
|
||||
@AliasFor(annotation = Entity.class, attribute = "name")
|
||||
String entityName();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user