DATAJPA-1168 - Introduce usage of nullable annotations for API validation.

Mark all packages with Spring Frameworks @NonNullApi. Add Spring's @Nullable to methods, parameters and fields that take or produce null values. Adapt using code to make sure the IDE can evaluate the null flow properly. Fix Javadoc in places where an invalid null handling policy was advertised. Strengthen null requirements for types that expose null-instances.

Introduce methods returning non-null values for required values that are checked for existence prior to retrieval.

Add generic types to IsAttributeNode factory methods.

Original Pull Request: #210
This commit is contained in:
Mark Paluch
2017-08-22 15:16:07 +02:00
committed by Christoph Strobl
parent 0273476ba6
commit 2e3e5f67bc
84 changed files with 790 additions and 399 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-2017 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.
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.persistence.criteria.CriteriaBuilder;
@@ -35,8 +36,10 @@ import javax.persistence.metamodel.SingularAttribute;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
import org.springframework.data.repository.core.support.ExampleMatcherAccessor;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -60,7 +63,7 @@ public class QueryByExamplePredicateBuilder {
private static final Set<PersistentAttributeType> ASSOCIATION_TYPES;
static {
ASSOCIATION_TYPES = new HashSet<PersistentAttributeType>(Arrays.asList(PersistentAttributeType.MANY_TO_MANY,
ASSOCIATION_TYPES = new HashSet<>(Arrays.asList(PersistentAttributeType.MANY_TO_MANY,
PersistentAttributeType.MANY_TO_ONE, PersistentAttributeType.ONE_TO_MANY, PersistentAttributeType.ONE_TO_ONE));
}
@@ -100,7 +103,7 @@ public class QueryByExamplePredicateBuilder {
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type, Object value,
Class<?> probeType, ExampleMatcherAccessor exampleAccessor, PathNode currentNode) {
List<Predicate> predicates = new ArrayList<Predicate>();
List<Predicate> predicates = new ArrayList<>();
DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper(value);
for (SingularAttribute attribute : type.getSingularAttributes()) {
@@ -111,10 +114,11 @@ public class QueryByExamplePredicateBuilder {
continue;
}
Object attributeValue = exampleAccessor.getValueTransformerForPath(currentPath)
.convert(beanWrapper.getPropertyValue(attribute.getName()));
PropertyValueTransformer transformer = exampleAccessor.getValueTransformerForPath(currentPath);
Optional<Object> optionalValue = transformer
.apply(Optional.ofNullable(beanWrapper.getPropertyValue(attribute.getName())));
if (attributeValue == null) {
if (!optionalValue.isPresent()) {
if (exampleAccessor.getNullHandler().equals(ExampleMatcher.NullHandler.INCLUDE)) {
predicates.add(cb.isNull(from.get(attribute)));
@@ -122,6 +126,8 @@ public class QueryByExamplePredicateBuilder {
continue;
}
Object attributeValue = optionalValue.get();
if (attribute.getPersistentAttributeType().equals(PersistentAttributeType.EMBEDDED)) {
predicates.addAll(getPredicates(currentPath, cb, from.get(attribute.getName()),
@@ -132,8 +138,8 @@ public class QueryByExamplePredicateBuilder {
if (isAssociation(attribute)) {
if (!(from instanceof From)) {
throw new JpaSystemException(new IllegalArgumentException(
String.format("Unexpected path type for %s. Found %s where From.class was expected.", currentPath, from)));
throw new JpaSystemException(new IllegalArgumentException(String
.format("Unexpected path type for %s. Found %s where From.class was expected.", currentPath, from)));
}
PathNode node = currentNode.add(attribute.getName(), attributeValue);
@@ -197,11 +203,11 @@ public class QueryByExamplePredicateBuilder {
private static class PathNode {
String name;
PathNode parent;
List<PathNode> siblings = new ArrayList<PathNode>();;
Object value;
@Nullable PathNode parent;
List<PathNode> siblings = new ArrayList<>();
@Nullable Object value;
public PathNode(String edge, PathNode parent, Object value) {
PathNode(String edge, @Nullable PathNode parent, @Nullable Object value) {
this.name = edge;
this.parent = parent;
@@ -222,14 +228,14 @@ public class QueryByExamplePredicateBuilder {
}
String identityHex = ObjectUtils.getIdentityHexString(value);
PathNode tmp = parent;
PathNode current = parent;
while (tmp != null) {
while (current != null) {
if (ObjectUtils.getIdentityHexString(tmp.value).equals(identityHex)) {
if (ObjectUtils.getIdentityHexString(current.value).equals(identityHex)) {
return true;
}
tmp = tmp.parent;
current = current.parent;
}
return false;

View File

@@ -0,0 +1,7 @@
/**
* Spring Data JPA specific converter infrastructure.
*/
@NonNullApi
package org.springframework.data.jpa.convert;
import org.springframework.lang.NonNullApi;

View File

@@ -0,0 +1,7 @@
/**
* Spring Data JPA specific JSR-310 converters.
*/
@NonNullApi
package org.springframework.data.jpa.convert.threeten;
import org.springframework.lang.NonNullApi;

View File

@@ -0,0 +1,7 @@
/**
* Spring Data JPA specific ThreeTenBp converters.
*/
@NonNullApi
package org.springframework.data.jpa.convert.threetenbp;
import org.springframework.lang.NonNullApi;

View File

@@ -27,12 +27,14 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.springframework.data.domain.Auditable;
import org.springframework.lang.Nullable;
/**
* Abstract base class for auditable entities. Stores the audition values in persistent fields.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @param <U> the auditing type. Typically some kind of user.
* @param <PK> the type of the auditing type's idenifier
*/
@@ -43,16 +45,16 @@ public abstract class AbstractAuditable<U, PK extends Serializable> extends Abst
private static final long serialVersionUID = 141481953116476081L;
@ManyToOne //
private U createdBy;
private @Nullable U createdBy;
@Temporal(TemporalType.TIMESTAMP) //
private Date createdDate;
private @Nullable Date createdDate;
@ManyToOne //
private U lastModifiedBy;
private @Nullable U lastModifiedBy;
@Temporal(TemporalType.TIMESTAMP) //
private Date lastModifiedDate;
private @Nullable Date lastModifiedDate;
/*
* (non-Javadoc)

View File

@@ -23,6 +23,7 @@ import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.springframework.data.domain.Persistable;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
/**
@@ -31,6 +32,7 @@ import org.springframework.util.ClassUtils;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
* @param <PK> the type of the identifier.
*/
@MappedSuperclass
@@ -38,13 +40,13 @@ public abstract class AbstractPersistable<PK extends Serializable> implements Pe
private static final long serialVersionUID = -5554308939380869754L;
@Id @GeneratedValue private PK id;
@Id @GeneratedValue private @Nullable PK id;
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Persistable#getId()
*/
public PK getId() {
public @Nullable PK getId() {
return id;
}
@@ -53,7 +55,7 @@ public abstract class AbstractPersistable<PK extends Serializable> implements Pe
*
* @param id the id to set
*/
protected void setId(final PK id) {
protected void setId(@Nullable PK id) {
this.id = id;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2017 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,6 +25,7 @@ import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.PluralAttribute;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -81,7 +82,7 @@ public class JpaSort extends Sort {
}
@SuppressWarnings("deprecation")
private JpaSort(List<Order> orders, Direction direction, List<Path<?, ?>> paths) {
private JpaSort(List<Order> orders, @Nullable Direction direction, List<Path<?, ?>> paths) {
super(combine(orders, direction, paths));
}
@@ -97,7 +98,7 @@ public class JpaSort extends Sort {
* @param attributes must not be {@literal null}.
* @return
*/
public JpaSort and(Direction direction, Attribute<?, ?>... attributes) {
public JpaSort and(@Nullable Direction direction, Attribute<?, ?>... attributes) {
Assert.notNull(attributes, "Attributes must not be null!");
@@ -111,7 +112,7 @@ public class JpaSort extends Sort {
* @param paths must not be {@literal null}.
* @return
*/
public JpaSort and(Direction direction, Path<?, ?>... paths) {
public JpaSort and(@Nullable Direction direction, Path<?, ?>... paths) {
Assert.notNull(paths, "Paths must not be null!");
@@ -131,7 +132,7 @@ public class JpaSort extends Sort {
* @param properties must not be {@literal null} or empty.
* @return
*/
public JpaSort andUnsafe(Direction direction, String... properties) {
public JpaSort andUnsafe(@Nullable Direction direction, String... properties) {
Assert.notEmpty(properties, "Properties must not be null!");
@@ -168,7 +169,7 @@ public class JpaSort extends Sort {
return paths;
}
private static List<Order> combine(List<Order> orders, Direction direction, List<Path<?, ?>> paths) {
private static List<Order> combine(List<Order> orders, @Nullable Direction direction, List<Path<?, ?>> paths) {
List<Order> result = new ArrayList<Sort.Order>(orders);
@@ -331,7 +332,7 @@ public class JpaSort extends Sort {
* @param direction can be {@literal null}, will default to {@link Sort#DEFAULT_DIRECTION}.
* @param property must not be {@literal null}.
*/
private JpaOrder(Direction direction, String property) {
private JpaOrder(@Nullable Direction direction, String property) {
this(direction, property, NullHandling.NATIVE);
}
@@ -343,11 +344,11 @@ public class JpaSort extends Sort {
* @param property must not be {@literal null}.
* @param nullHandlingHint can be {@literal null}, will default to {@link NullHandling#NATIVE}.
*/
private JpaOrder(Direction direction, String property, NullHandling nullHandlingHint) {
private JpaOrder(@Nullable Direction direction, String property, NullHandling nullHandlingHint) {
this(direction, property, nullHandlingHint, false, true);
}
private JpaOrder(Direction direction, String property, NullHandling nullHandling, boolean ignoreCase,
private JpaOrder(@Nullable Direction direction, String property, NullHandling nullHandling, boolean ignoreCase,
boolean unsafe) {
super(direction, property, nullHandling);

View File

@@ -24,6 +24,8 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.lang.Nullable;
/**
* Specification in the sense of Domain Driven Design.
*
@@ -31,6 +33,7 @@ import javax.persistence.criteria.Root;
* @author Thomas Darimont
* @author Krzysztof Rzymkowski
* @author Sebastian Staudt
* @author Mark Paluch
*/
@SuppressWarnings("deprecation")
public interface Specification<T> extends Serializable {
@@ -91,5 +94,6 @@ public interface Specification<T> extends Serializable {
* @param query
* @return a {@link Predicate}, may be {@literal null}.
*/
@Nullable
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}

View File

@@ -24,12 +24,16 @@ import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Helper class to easily combine {@link Specification} instances.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Sebastian Staudt
* @author Mark Paluch
* @deprecated since 2.0, use factory methods on {@link Specification} instead.
*/
@Deprecated
@@ -37,14 +41,14 @@ public class Specifications<T> implements Specification<T>, Serializable {
private static final long serialVersionUID = 1L;
private final Specification<T> spec;
private final @Nullable Specification<T> spec;
/**
* Creates a new {@link Specifications} wrapper for the given {@link Specification}.
*
* @param spec can be {@literal null}.
*/
Specifications(Specification<T> spec) {
Specifications(@Nullable Specification<T> spec) {
this.spec = spec;
}
@@ -57,7 +61,7 @@ public class Specifications<T> implements Specification<T>, Serializable {
* @return
*/
@Deprecated
public static <T> Specifications<T> where(Specification<T> spec) {
public static <T> Specifications<T> where(@Nullable Specification<T> spec) {
return new Specifications<>(spec);
}
@@ -70,7 +74,7 @@ public class Specifications<T> implements Specification<T>, Serializable {
* @return
*/
@Deprecated
public Specifications<T> and(Specification<T> other) {
public Specifications<T> and(@Nullable Specification<T> other) {
return new Specifications<>(composed(spec, other, AND));
}
@@ -83,7 +87,7 @@ public class Specifications<T> implements Specification<T>, Serializable {
* @return
*/
@Deprecated
public Specifications<T> or(Specification<T> other) {
public Specifications<T> or(@Nullable Specification<T> other) {
return new Specifications<>(composed(spec, other, OR));
}
@@ -96,7 +100,7 @@ public class Specifications<T> implements Specification<T>, Serializable {
* @return
*/
@Deprecated
public static <T> Specifications<T> not(Specification<T> spec) {
public static <T> Specifications<T> not(@Nullable Specification<T> spec) {
return new Specifications<>(negated(spec));
}
@@ -104,6 +108,7 @@ public class Specifications<T> implements Specification<T>, Serializable {
* (non-Javadoc)
* @see org.springframework.data.jpa.domain.Specification#toPredicate(javax.persistence.criteria.Root, javax.persistence.criteria.CriteriaQuery, javax.persistence.criteria.CriteriaBuilder)
*/
@Nullable
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return spec == null ? null : spec.toPredicate(root, query, builder);
}
@@ -133,11 +138,11 @@ public class Specifications<T> implements Specification<T>, Serializable {
abstract Predicate combine(CriteriaBuilder builder, Predicate lhs, Predicate rhs);
}
static <T> Specification<T> negated(Specification<T> spec) {
static <T> Specification<T> negated(@Nullable Specification<T> spec) {
return (root, query, builder) -> spec == null ? null : builder.not(spec.toPredicate(root, query, builder));
}
static <T> Specification<T> composed(Specification<T> lhs, Specification<T> rhs, CompositionType compositionType) {
static <T> Specification<T> composed(@Nullable Specification<T> lhs, @Nullable Specification<T> rhs, CompositionType compositionType) {
return (root, query, builder) -> {

View File

@@ -1,5 +1,7 @@
/**
* JPA specific support classes to implement domain classes.
*/
@NonNullApi
package org.springframework.data.jpa.domain;
import org.springframework.lang.NonNullApi;

View File

@@ -22,6 +22,7 @@ import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.domain.Auditable;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -55,11 +56,12 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
@Configurable
public class AuditingEntityListener {
private ObjectFactory<AuditingHandler> handler;
private @Nullable ObjectFactory<AuditingHandler> handler;
/**
* Configures the {@link AuditingHandler} to be used to set the current auditor on the domain types touched.
@@ -84,7 +86,11 @@ public class AuditingEntityListener {
Assert.notNull(target, "Entity must not be null!");
if (handler != null) {
handler.getObject().markCreated(target);
AuditingHandler object = handler.getObject();
if (object != null) {
object.markCreated(target);
}
}
}
@@ -100,7 +106,11 @@ public class AuditingEntityListener {
Assert.notNull(target, "Entity must not be null!");
if (handler != null) {
handler.getObject().markModified(target);
AuditingHandler object = handler.getObject();
if (object != null) {
object.markModified(target);
}
}
}
}

View File

@@ -1,5 +1,7 @@
/**
* Implementation classes for auditing with JPA.
*/
@NonNullApi
package org.springframework.data.jpa.domain.support;
import org.springframework.lang.NonNullApi;

View File

@@ -26,6 +26,7 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -33,6 +34,7 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.3
*/
public class JpaMetamodelMappingContext
@@ -73,6 +75,11 @@ public class JpaMetamodelMappingContext
SimpleTypeHolder simpleTypeHolder) {
Metamodel metamodel = getMetamodelFor(owner.getType());
if (metamodel == null) {
throw new IllegalStateException(String.format("Metamodel for %s not available!", owner.getType()));
}
return new JpaPersistentPropertyImpl(metamodel, property, owner, simpleTypeHolder);
}
@@ -91,6 +98,7 @@ public class JpaMetamodelMappingContext
* @param type
* @return
*/
@Nullable
private Metamodel getMetamodelFor(Class<?> type) {
for (Metamodel model : models) {

View File

@@ -31,6 +31,7 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @author Greg Turnquist
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.3
*/
class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentProperty>
@@ -112,7 +113,7 @@ class JpaPersistentEntityImpl<T> extends BasicPersistentEntity<T, JpaPersistentP
* @param bean must not be {@literal null}.
* @param proxyIdAccessor must not be {@literal null}.
*/
public JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean,
JpaProxyAwareIdentifierAccessor(JpaPersistentEntity<?> entity, Object bean,
ProxyIdAccessor proxyIdAccessor) {
super(entity, bean);

View File

@@ -47,6 +47,7 @@ import org.springframework.data.mapping.model.Property;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -55,6 +56,7 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @author Greg Turnquist
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.3
*/
class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPersistentProperty>
@@ -88,8 +90,8 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
UPDATEABLE_ANNOTATIONS = Collections.unmodifiableSet(annotations);
}
private final Boolean usePropertyAccess;
private final TypeInformation<?> associationTargetType;
private final @Nullable Boolean usePropertyAccess;
private final @Nullable TypeInformation<?> associationTargetType;
private final boolean updateable;
private final JpaMetamodel metamodel;
@@ -220,6 +222,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
*
* @return
*/
@Nullable
private Boolean detectPropertyAccess() {
org.springframework.data.annotation.AccessType accessType = findAnnotation(
@@ -255,6 +258,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
*
* @return
*/
@Nullable
private TypeInformation<?> detectAssociationTargetType() {
if (!isAssociation()) {
@@ -287,7 +291,7 @@ class JpaPersistentPropertyImpl extends AnnotationBasedPersistentProperty<JpaPer
*
* @return
*/
private final boolean detectUpdatability() {
private boolean detectUpdatability() {
for (Class<? extends Annotation> annotationType : UPDATEABLE_ANNOTATIONS) {

View File

@@ -1,5 +1,7 @@
/**
* JPA specific support classes for the Spring Data mapping subsystem.
*/
@NonNullApi
package org.springframework.data.jpa.mapping;
import org.springframework.lang.NonNullApi;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016 the original author or authors.
* Copyright 2016-2017 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,7 @@ import java.util.Arrays;
import java.util.List;
import org.hibernate.Query;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -27,6 +28,8 @@ import org.springframework.util.ReflectionUtils;
* Utility functions to work with Hibernate. Mostly using reflection to make sure common functionality can be executed
* against all the Hibernate version we support.
*
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.10.2
* @soundtrack Benny Greb - Soulfood (Live, https://www.youtube.com/watch?v=9_ErMa_CtSw)
*/
@@ -34,10 +37,9 @@ public abstract class HibernateUtils {
private static final List<String> TYPES = Arrays.asList("org.hibernate.jpa.HibernateQuery",
"org.hibernate.ejb.HibernateQuery");
private static final Method GET_HIBERNATE_QUERY;
private static final Class<?> HIBERNATE_QUERY_INTERFACE;
private static final Method QUERY_STRING_METHOD;
private static final @Nullable Method GET_HIBERNATE_QUERY;
private static final @Nullable Class<?> HIBERNATE_QUERY_INTERFACE;
private static final @Nullable Method QUERY_STRING_METHOD;
private HibernateUtils() {}
@@ -73,6 +75,7 @@ public abstract class HibernateUtils {
* @param query
* @return
*/
@Nullable
public static String getHibernateQuery(Object query) {
if (HIBERNATE_QUERY_INTERFACE != null && QUERY_STRING_METHOD != null
@@ -84,6 +87,12 @@ public abstract class HibernateUtils {
query = ((javax.persistence.Query) query).unwrap(HIBERNATE_QUERY_INTERFACE);
}
return ((Query) ReflectionUtils.invokeMethod(GET_HIBERNATE_QUERY, query)).getQueryString();
if (GET_HIBERNATE_QUERY == null) {
throw new IllegalStateException(
"Cannot invoke getHibernateQuery(…). No underlying method for a reflective call found.");
}
Query q = (Query) ReflectionUtils.invokeMethod(GET_HIBERNATE_QUERY, query);
return q == null ? "" : q.getQueryString();
}
}

View File

@@ -21,6 +21,7 @@ import static org.springframework.data.jpa.provider.PersistenceProvider.Constant
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.NoSuchElementException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@@ -32,6 +33,7 @@ import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.proxy.HibernateProxy;
import org.springframework.data.util.CloseableIterator;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
@@ -41,6 +43,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
@@ -94,8 +97,9 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
* (non-Javadoc)
* @see org.springframework.data.jpa.provider.PersistenceProvider#potentiallyConvertEmptyCollection(java.util.Collection)
*/
@Nullable
@Override
public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
public <T> Collection<T> potentiallyConvertEmptyCollection(@Nullable Collection<T> collection) {
return collection == null || collection.isEmpty() ? null : collection;
}
@@ -132,6 +136,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Nullable
@Override
public Object getIdentifierFrom(Object entity) {
return null;
@@ -140,8 +145,9 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
/* (non-Javadoc)
* @see org.springframework.data.jpa.provider.PersistenceProvider#potentiallyConvertEmptyCollection(java.util.Collection)
*/
@Nullable
@Override
public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
public <T> Collection<T> potentiallyConvertEmptyCollection(@Nullable Collection<T> collection) {
return collection == null || collection.isEmpty() ? null : collection;
}
@@ -164,6 +170,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.QueryExtractor#extractQueryString(javax.persistence.Query)
*/
@Nullable
@Override
public String extractQueryString(Query query) {
return null;
@@ -191,6 +198,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.ProxyIdAccessor#getIdentifierFrom(java.lang.Object)
*/
@Nullable
@Override
public Object getIdentifierFrom(Object entity) {
return null;
@@ -331,7 +339,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
* @param collection
* @return
*/
public <T> Collection<T> potentiallyConvertEmptyCollection(Collection<T> collection) {
@Nullable
public <T> Collection<T> potentiallyConvertEmptyCollection(@Nullable Collection<T> collection) {
return collection;
}
@@ -350,7 +359,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
*/
private static class HibernateScrollableResultsIterator implements CloseableIterator<Object> {
private final ScrollableResults scrollableResults;
private final @Nullable ScrollableResults scrollableResults;
/**
* Creates a new {@link HibernateScrollableResultsIterator} for the given {@link Query}.
@@ -371,6 +380,10 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
@Override
public Object next() {
if (scrollableResults == null) {
throw new NoSuchElementException("No ScrollableResults");
}
Object[] row = scrollableResults.get();
return row.length == 1 ? row[0] : row;
@@ -382,7 +395,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
*/
@Override
public boolean hasNext() {
return scrollableResults == null ? false : scrollableResults.next();
return scrollableResults != null && scrollableResults.next();
}
/*
@@ -409,7 +422,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
@SuppressWarnings("unchecked")
private static class EclipseLinkScrollableResultsIterator<T> implements CloseableIterator<T> {
private final ScrollableCursor scrollableCursor;
private final @Nullable ScrollableCursor scrollableCursor;
/**
* Creates a new {@link EclipseLinkScrollableResultsIterator} for the given JPA {@link Query}.
@@ -429,7 +442,7 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
*/
@Override
public boolean hasNext() {
return scrollableCursor == null ? false : scrollableCursor.hasNext();
return scrollableCursor != null && scrollableCursor.hasNext();
}
/*
@@ -438,6 +451,11 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
*/
@Override
public T next() {
if (scrollableCursor == null) {
throw new NoSuchElementException("No ScrollableCursor");
}
return (T) scrollableCursor.next();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2017 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,10 +15,13 @@
*/
package org.springframework.data.jpa.provider;
import org.springframework.lang.Nullable;
/**
* Interface for a persistence provider specific accessor of identifiers held in proxies.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public interface ProxyIdAccessor {
@@ -37,5 +40,6 @@ public interface ProxyIdAccessor {
* @param entity must not be {@literal null}.
* @return
*/
@Nullable
Object getIdentifierFrom(Object entity);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2011 the original author or authors.
* Copyright 2008-2017 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,10 +17,13 @@ package org.springframework.data.jpa.provider;
import javax.persistence.Query;
import org.springframework.lang.Nullable;
/**
* Interface to hide different implementations to extract the original JPA query string from a {@link Query}.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public interface QueryExtractor {
@@ -31,6 +34,7 @@ public interface QueryExtractor {
* @param query
* @return the query string representing the query or {@literal null} if resolving is not possible.
*/
@Nullable
String extractQueryString(Query query);
/**

View File

@@ -0,0 +1,7 @@
/**
* JPA provider-specific utilities.
*/
@NonNullApi
package org.springframework.data.jpa.provider;
import org.springframework.lang.NonNullApi;

View File

@@ -22,6 +22,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
/**
* Interface to allow execution of {@link Specification}s based on the JPA criteria API.
@@ -38,7 +39,7 @@ public interface JpaSpecificationExecutor<T> {
* @return never {@literal null}.
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException if more than one entity found.
*/
Optional<T> findOne(Specification<T> spec);
Optional<T> findOne(@Nullable Specification<T> spec);
/**
* Returns all entities matching the given {@link Specification}.
@@ -46,25 +47,25 @@ public interface JpaSpecificationExecutor<T> {
* @param spec can be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec);
List<T> findAll(@Nullable Specification<T> spec);
/**
* Returns a {@link Page} of entities matching the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @param pageable can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return never {@literal null}.
*/
Page<T> findAll(Specification<T> spec, Pageable pageable);
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);
/**
* Returns all entities matching the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort can be {@literal null}.
* @param sort must not be {@literal null}.
* @return never {@literal null}.
*/
List<T> findAll(Specification<T> spec, Sort sort);
List<T> findAll(@Nullable Specification<T> spec, Sort sort);
/**
* Returns the number of instances that the given {@link Specification} will return.
@@ -72,5 +73,5 @@ public interface JpaSpecificationExecutor<T> {
* @param spec the {@link Specification} to count instances for. Can be {@literal null}.
* @return the number of instances.
*/
long count(Specification<T> spec);
long count(@Nullable Specification<T> spec);
}

View File

@@ -49,7 +49,7 @@ class JpaRepositoryBean<T> extends CdiRepositoryBean<T> {
* @param entityManagerBean must not be {@literal null}.
* @param qualifiers must not be {@literal null}.
* @param repositoryType must not be {@literal null}.
* @param detector can be {@literal null}.
* @param detector can be {@link Optional#empty()}.
*/
JpaRepositoryBean(BeanManager beanManager, Bean<EntityManager> entityManagerBean, Set<Annotation> qualifiers,
Class<T> repositoryType, Optional<CustomRepositoryImplementationDetector> detector) {

View File

@@ -123,6 +123,6 @@ public class JpaRepositoryExtension extends CdiRepositoryExtensionSupport {
// Construct and return the repository bean.
return new JpaRepositoryBean<T>(beanManager, entityManagerBean, qualifiers, repositoryType,
Optional.ofNullable(getCustomImplementationDetector()));
Optional.of(getCustomImplementationDetector()));
}
}

View File

@@ -1,5 +1,7 @@
/**
* CDI support for Spring Data JPA Repositories.
*/
@NonNullApi
package org.springframework.data.jpa.repository.cdi;
import org.springframework.lang.NonNullApi;

View File

@@ -1,3 +1,18 @@
/*
* Copyright 2017 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.config;
import java.util.Collection;
@@ -16,17 +31,19 @@ import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext;
import org.springframework.lang.Nullable;
/**
* {@link FactoryBean} to setup {@link JpaMetamodelMappingContext} instances from Spring configuration.
*
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.6
*/
class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetamodelMappingContext> implements
ApplicationContextAware {
class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetamodelMappingContext>
implements ApplicationContextAware {
private ListableBeanFactory beanFactory;
private @Nullable ListableBeanFactory beanFactory;
/*
* (non-Javadoc)
@@ -82,8 +99,12 @@ class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean<JpaMetam
*/
private Set<Metamodel> getMetamodels() {
Collection<EntityManagerFactory> factories = BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory,
EntityManagerFactory.class).values();
if (beanFactory == null) {
throw new IllegalStateException("BeanFactory must not be null!");
}
Collection<EntityManagerFactory> factories = BeanFactoryUtils
.beansOfTypeIncludingAncestors(beanFactory, EntityManagerFactory.class).values();
Set<Metamodel> metamodels = new HashSet<Metamodel>(factories.size());
for (EntityManagerFactory emf : factories) {

View File

@@ -55,12 +55,13 @@ import org.springframework.util.StringUtils;
* {@link PersistenceUnit} annotated properties and methods) as well as
* {@link PersistenceExceptionTranslationPostProcessor} to enable exception translation of persistence specific
* exceptions into Spring's {@link DataAccessException} hierarchy.
*
*
* @author Oliver Gierke
* @author Eberhard Wolff
* @author Gil Markham
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
@@ -68,7 +69,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
private static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
private static final String ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE = "enableDefaultTransactions";
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModuleName()
*/
@@ -86,7 +87,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
return JpaRepositoryFactoryBean.class.getName();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config14.RepositoryConfigurationExtensionSupport#getModulePrefix()
*/
@@ -95,7 +96,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
return getModuleName().toLowerCase(Locale.US);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingAnnotations()
*/
@@ -104,7 +105,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
return Arrays.asList(Entity.class, MappedSuperclass.class);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getIdentifyingTypes()
*/
@@ -113,7 +114,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
return Collections.<Class<?>> singleton(JpaRepository.class);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.RepositoryConfigurationSource)
*/
@@ -126,7 +127,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
builder.addPropertyReference("mappingContext", JPA_MAPPING_CONTEXT_BEAN_NAME);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource)
*/
@@ -139,7 +140,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
attributes.getBoolean(ENABLE_DEFAULT_TRANSACTIONS_ATTRIBUTE));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource)
*/
@@ -153,7 +154,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
}
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#registerBeansForRoot(org.springframework.beans.factory.support.BeanDefinitionRegistry, org.springframework.data.repository.config.RepositoryConfigurationSource)
*/
@@ -184,7 +185,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
/**
* Creates an anonymous factory to extract the actual {@link javax.persistence.EntityManager} from the
* {@link javax.persistence.EntityManagerFactory} bean name reference.
*
*
* @param config
* @param source
* @return
@@ -205,8 +206,7 @@ public class JpaRepositoryConfigExtension extends RepositoryConfigurationExtensi
private static String getEntityManagerBeanRef(RepositoryConfigurationSource config) {
Optional<String> entityManagerFactoryRef = config == null ? Optional.empty()
: config.getAttribute("entityManagerFactoryRef");
Optional<String> entityManagerFactoryRef = config.getAttribute("entityManagerFactoryRef");
return entityManagerFactoryRef.orElse("entityManagerFactory");
}
}

View File

@@ -1,5 +1,7 @@
/**
* Classes for JPA namespace configuration.
*/
@NonNullApi
package org.springframework.data.jpa.repository.config;
import org.springframework.lang.NonNullApi;

View File

@@ -1,5 +1,7 @@
/**
* Interfaces and annotations for JPA specific repositories.
*/
@NonNullApi
package org.springframework.data.jpa.repository;
import org.springframework.lang.NonNullApi;

View File

@@ -42,11 +42,12 @@ import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.util.Lazy;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Abstract base class to implement {@link RepositoryQuery}s.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
@@ -63,7 +64,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}.
*
*
* @param method
* @param em
*/
@@ -81,13 +82,14 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod()
*/
@Override
public JpaQueryMethod getQueryMethod() {
return method;
}
/**
* Returns the {@link EntityManager}.
*
*
* @return will never be {@literal null}.
*/
protected EntityManager getEntityManager() {
@@ -96,7 +98,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Returns the {@link JpaMetamodel}.
*
*
* @return
*/
protected JpaMetamodel getMetamodel() {
@@ -107,6 +109,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* (non-Javadoc)
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
*/
@Nullable
@Override
public Object execute(Object[] parameters) {
return doExecute(getExecution(), parameters);
}
@@ -116,6 +120,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
* @param values
* @return
*/
@Nullable
private Object doExecute(JpaQueryExecution execution, Object[] values) {
Object result = execution.execute(this, values);
@@ -147,7 +152,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Applies the declared query hints to the given query.
*
*
* @param query
* @return
*/
@@ -162,7 +167,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Protected to be able to customize in sub-classes.
*
*
* @param query must not be {@literal null}.
* @param hint must not be {@literal null}.
*/
@@ -176,7 +181,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Applies the {@link LockModeType} provided by the {@link JpaQueryMethod} to the given {@link Query}.
*
*
* @param query must not be {@literal null}.
* @param method must not be {@literal null}.
* @return
@@ -198,7 +203,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Configures the {@link javax.persistence.EntityGraph} to use for the given {@link JpaQueryMethod} if the
* {@link EntityGraph} annotation is present.
*
*
* @param query must not be {@literal null}.
* @param method must not be {@literal null}.
* @return
@@ -225,7 +230,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Creates a {@link Query} instance for the given values.
*
*
* @param values must not be {@literal null}.
* @return
*/
@@ -233,7 +238,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Creates a {@link TypedQuery} for counting using the given values.
*
*
* @param values must not be {@literal null}.
* @return
*/
@@ -245,7 +250,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Creates a new {@link TupleConverter} for the given {@link ReturnedType}.
*
*
* @param type must not be {@literal null}.
*/
public TupleConverter(ReturnedType type) {
@@ -255,7 +260,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
this.type = type;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.core.convert.converter.Converter#convert(java.lang.Object)
*/
@@ -267,7 +272,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
}
Tuple tuple = (Tuple) source;
Map<String, Object> result = new HashMap<String, Object>();
Map<String, Object> result = new HashMap<>();
List<TupleElement<?>> elements = tuple.getElements();
if (elements.size() == 1) {

View File

@@ -23,7 +23,7 @@ import org.springframework.util.StringUtils;
/**
* Default implementation for {@link JpaEntityMetadata}.
*
*
* @author Oliver Gierke
* @author Christoph Strobl
*/
@@ -33,7 +33,7 @@ public class DefaultJpaEntityMetadata<T> implements JpaEntityMetadata<T> {
/**
* Creates a new {@link DefaultJpaEntityMetadata} for the given domain type.
*
*
* @param domainType must not be {@literal null}.
*/
public DefaultJpaEntityMetadata(Class<T> domainType) {
@@ -42,7 +42,7 @@ public class DefaultJpaEntityMetadata<T> implements JpaEntityMetadata<T> {
this.domainType = domainType;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.EntityMetadata#getJavaType()
*/
@@ -55,11 +55,10 @@ public class DefaultJpaEntityMetadata<T> implements JpaEntityMetadata<T> {
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaEntityMetadata#getEntityName()
*/
@Override
public String getEntityName() {
Entity entity = AnnotatedElementUtils.findMergedAnnotation(domainType, Entity.class);
boolean hasName = null != entity && StringUtils.hasText(entity.name());
return hasName ? entity.name() : domainType.getSimpleName();
return null != entity && StringUtils.hasText(entity.name()) ? entity.name() : domainType.getSimpleName();
}
}

View File

@@ -27,6 +27,7 @@ import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.Subgraph;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -39,11 +40,12 @@ import org.springframework.util.StringUtils;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.6
*/
public class Jpa21Utils {
private static final Method GET_ENTITY_GRAPH_METHOD;
private static final @Nullable Method GET_ENTITY_GRAPH_METHOD;
private static final boolean JPA21_AVAILABLE = ClassUtils.isPresent("javax.persistence.NamedEntityGraph",
Jpa21Utils.class.getClassLoader());
@@ -69,7 +71,7 @@ public class Jpa21Utils {
* @return a {@code Map} with the hints or an empty {@code Map} if no hints were found.
* @since 1.8
*/
public static Map<String, Object> tryGetFetchGraphHints(EntityManager em, JpaEntityGraph entityGraph,
public static Map<String, Object> tryGetFetchGraphHints(EntityManager em, @Nullable JpaEntityGraph entityGraph,
Class<?> entityType) {
if (entityGraph == null) {
@@ -95,6 +97,7 @@ public class Jpa21Utils {
* @param entityType must not be {@literal null}.
* @return the {@link EntityGraph} described by the given {@code entityGraph}.
*/
@Nullable
private static EntityGraph<?> tryGetFetchGraph(EntityManager em, JpaEntityGraph jpaEntityGraph, Class<?> entityType) {
Assert.notNull(em, "EntityManager must not be null!");
@@ -157,7 +160,8 @@ public class Jpa21Utils {
}
}
private static void createGraph(String[] pathComponents, int offset, EntityGraph<?> root, Subgraph<?> parent) {
private static void createGraph(String[] pathComponents, int offset, EntityGraph<?> root,
@Nullable Subgraph<?> parent) {
String attributeName = pathComponents[offset];
@@ -216,8 +220,9 @@ public class Jpa21Utils {
* @param parent
* @return {@literal null} if not found.
*/
@Nullable
private static AttributeNode<?> findAttributeNode(String attributeNodeName, EntityGraph<?> entityGraph,
Subgraph<?> parent) {
@Nullable Subgraph<?> parent) {
return findAttributeNode(attributeNodeName,
parent != null ? parent.getAttributeNodes() : entityGraph.getAttributeNodes());
}
@@ -230,6 +235,7 @@ public class Jpa21Utils {
* @param nodes
* @return {@literal null} if not found.
*/
@Nullable
private static AttributeNode<?> findAttributeNode(String attributeNodeName, List<AttributeNode<?>> nodes) {
for (AttributeNode<?> node : nodes) {
@@ -249,6 +255,7 @@ public class Jpa21Utils {
* @param node
* @return
*/
@Nullable
private static Subgraph<?> getSubgraph(AttributeNode<?> node) {
return node.getSubgraphs().isEmpty() ? null : node.getSubgraphs().values().iterator().next();
}

View File

@@ -24,12 +24,14 @@ import javax.persistence.criteria.Root;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
/**
* Special {@link JpaQueryCreator} that creates a count projecting query.
*
* @author Oliver Gierke
* @author Marc Lefrançois
* @author Mark Paluch
*/
public class JpaCountQueryCreator extends JpaQueryCreator {
@@ -61,7 +63,7 @@ public class JpaCountQueryCreator extends JpaQueryCreator {
*/
@Override
@SuppressWarnings("unchecked")
protected CriteriaQuery<? extends Object> complete(Predicate predicate, Sort sort,
protected CriteriaQuery<? extends Object> complete(@Nullable Predicate predicate, Sort sort,
CriteriaQuery<? extends Object> query, CriteriaBuilder builder, Root<?> root) {
CriteriaQuery<? extends Object> select = query.select(getCountQuery(query, builder, root));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2015 the original author or authors.
* Copyright 2014-2017 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,7 @@ import java.util.List;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.data.jpa.repository.EntityGraph.EntityGraphType;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -27,6 +28,7 @@ import org.springframework.util.StringUtils;
* EntityGraph configuration for JPA 2.1 {@link EntityGraph}s.
*
* @author Thomas Darimont
* @author Mark Paluch
* @since 1.6
*/
public class JpaEntityGraph {
@@ -56,7 +58,7 @@ public class JpaEntityGraph {
* @param attributePaths may be {@literal null}.
* @since 1.9
*/
public JpaEntityGraph(String name, EntityGraphType type, String[] attributePaths) {
public JpaEntityGraph(String name, EntityGraphType type, @Nullable String[] attributePaths) {
Assert.hasText(name, "The name of an EntityGraph must not be null or empty!");
Assert.notNull(type, "FetchGraphType must not be null!");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2017 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.
@@ -26,11 +26,13 @@ import org.springframework.data.jpa.repository.Temporal;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.lang.Nullable;
/**
* Custom extension of {@link Parameters} discovering additional query parameter annotations.
*
* @author Thomas Darimont
* @author Mark Paluch
*/
public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
@@ -73,8 +75,8 @@ public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
*/
static class JpaParameter extends Parameter {
private final Temporal annotation;
private TemporalType temporalType;
private final @Nullable Temporal annotation;
private @Nullable TemporalType temporalType;
/**
* Creates a new {@link JpaParameter}.
@@ -89,8 +91,8 @@ public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
this.temporalType = null;
if (!isDateParameter() && hasTemporalParamAnnotation()) {
throw new IllegalArgumentException(Temporal.class.getSimpleName()
+ " annotation is only allowed on Date parameter!");
throw new IllegalArgumentException(
Temporal.class.getSimpleName() + " annotation is only allowed on Date parameter!");
}
}
@@ -106,14 +108,15 @@ public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
/**
* @return {@literal true} if this parameter is of type {@link Date} and has an {@link Temporal} annotation.
*/
public boolean isTemporalParameter() {
boolean isTemporalParameter() {
return isDateParameter() && hasTemporalParamAnnotation();
}
/**
* @return the {@link TemporalType} on the {@link Temporal} annotation of the given {@link Parameter}.
*/
public TemporalType getTemporalType() {
@Nullable
TemporalType getTemporalType() {
if (temporalType == null) {
this.temporalType = annotation == null ? null : annotation.value();
@@ -122,6 +125,22 @@ public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
return this.temporalType;
}
/**
* @return the required {@link TemporalType} on the {@link Temporal} annotation of the given {@link Parameter}.
* @throws IllegalStateException if the parameter does not define a {@link TemporalType}.
* @since 2.0
*/
TemporalType getRequiredTemporalType() throws IllegalStateException {
TemporalType temporalType = getTemporalType();
if (temporalType != null) {
return temporalType;
}
throw new IllegalStateException(String.format("Required temporal type not found for %s!", getType()));
}
private boolean hasTemporalParamAnnotation() {
return annotation != null;
}

View File

@@ -42,14 +42,16 @@ import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Query creator to create a {@link CriteriaQuery} from a {@link PartTree}.
*
*
* @author Oliver Gierke
* @author Mark Paluch
* @author Michael Cramer
* @author Mark Paluch
*/
public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extends Object>, Predicate> {
@@ -62,7 +64,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Create a new {@link JpaQueryCreator}.
*
*
* @param tree must not be {@literal null}.
* @param type must not be {@literal null}.
* @param builder must not be {@literal null}.
@@ -85,7 +87,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Creates the {@link CriteriaQuery} to apply predicates on.
*
*
* @param builder will never be {@literal null}.
* @param type will never be {@literal null}.
* @return must not be {@literal null}.
@@ -100,7 +102,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Returns all {@link javax.persistence.criteria.ParameterExpression} created when creating the query.
*
*
* @return the parameterExpressions
*/
public List<ParameterMetadata<?>> getParameterExpressions() {
@@ -148,7 +150,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Template method to finalize the given {@link Predicate} using the given {@link CriteriaQuery} and
* {@link CriteriaBuilder}.
*
*
* @param predicate
* @param sort
* @param query
@@ -156,12 +158,12 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
* @return
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
protected CriteriaQuery<? extends Object> complete(Predicate predicate, Sort sort,
protected CriteriaQuery<? extends Object> complete(@Nullable Predicate predicate, Sort sort,
CriteriaQuery<? extends Object> query, CriteriaBuilder builder, Root<?> root) {
if (returnedType.needsCustomConstruction()) {
List<Selection<?>> selections = new ArrayList<Selection<?>>();
List<Selection<?>> selections = new ArrayList<>();
for (String property : returnedType.getInputProperties()) {
@@ -207,7 +209,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Simple builder to contain logic to create JPA {@link Predicate}s from {@link Part}s.
*
*
* @author Phil Webb
* @author Oliver Gierke
*/
@@ -219,7 +221,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Creates a new {@link PredicateBuilder} for the given {@link Part} and {@link Root}.
*
*
* @param part must not be {@literal null}.
* @param root must not be {@literal null}.
*/
@@ -233,7 +235,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Builds a JPA {@link Predicate} from the underlying {@link Part}.
*
*
* @return
*/
public Predicate build() {
@@ -331,7 +333,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Applies an {@code UPPERCASE} conversion to the given {@link Expression} in case the underlying {@link Part}
* requires ignoring case.
*
*
* @param expression must not be {@literal null}.
* @return
*/
@@ -364,7 +366,7 @@ public class JpaQueryCreator extends AbstractQueryCreator<CriteriaQuery<? extend
/**
* Returns a path to a {@link Comparable}.
*
*
* @param root
* @param part
* @return

View File

@@ -39,6 +39,7 @@ import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -74,6 +75,7 @@ public abstract class JpaQueryExecution {
* @param values must not be {@literal null}.
* @return
*/
@Nullable
public Object execute(AbstractJpaQuery query, Object[] values) {
Assert.notNull(query, "AbstractJpaQuery must not be null!");
@@ -109,6 +111,7 @@ public abstract class JpaQueryExecution {
* @param values
* @return
*/
@Nullable
protected abstract Object doExecute(AbstractJpaQuery query, Object[] values);
/**
@@ -212,7 +215,7 @@ public abstract class JpaQueryExecution {
*/
static class ModifyingExecution extends JpaQueryExecution {
private final EntityManager em;
private final @Nullable EntityManager em;
/**
* Creates an execution that automatically clears the given {@link EntityManager} after execution if the given
@@ -220,7 +223,7 @@ public abstract class JpaQueryExecution {
*
* @param em
*/
public ModifyingExecution(JpaQueryMethod method, EntityManager em) {
public ModifyingExecution(JpaQueryMethod method, @Nullable EntityManager em) {
Class<?> returnType = method.getReturnType();
@@ -363,10 +366,7 @@ public abstract class JpaQueryExecution {
Class<?> optionalType = ClassUtils.forName("java.util.Optional", classLoader);
conversionService.removeConvertible(Object.class, optionalType);
} catch (ClassNotFoundException e) {
return;
} catch (LinkageError e) {
return;
} catch (ClassNotFoundException | LinkageError o_O) {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2017 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,11 +24,13 @@ import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
/**
* Factory to create the appropriate {@link RepositoryQuery} for a {@link JpaQueryMethod}.
*
* @author Thomas Darimont
* @author Mark Paluch
*/
enum JpaQueryFactory {
@@ -46,6 +48,7 @@ enum JpaQueryFactory {
* @param evaluationContextProvider
* @return the {@link RepositoryQuery} derived from the annotation or {@code null} if no annotation found.
*/
@Nullable
AbstractJpaQuery fromQueryAnnotation(JpaQueryMethod method, EntityManager em,
EvaluationContextProvider evaluationContextProvider) {
@@ -62,7 +65,8 @@ enum JpaQueryFactory {
* @param evaluationContextProvider
* @return
*/
AbstractJpaQuery fromMethodWithQueryString(JpaQueryMethod method, EntityManager em, String queryString,
@Nullable
AbstractJpaQuery fromMethodWithQueryString(JpaQueryMethod method, EntityManager em, @Nullable String queryString,
EvaluationContextProvider evaluationContextProvider) {
if (queryString == null) {
@@ -80,6 +84,7 @@ enum JpaQueryFactory {
* @param em must not be {@literal null}.
* @return
*/
@Nullable
public StoredProcedureJpaQuery fromProcedureAnnotation(JpaQueryMethod method, EntityManager em) {
if (!method.isProcedureQuery()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2016 the original author or authors.
* Copyright 2008-2017 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,13 +28,15 @@ import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* Query lookup strategy to execute finders.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public final class JpaQueryLookupStrategy {
@@ -45,7 +47,7 @@ public final class JpaQueryLookupStrategy {
/**
* Base class for {@link QueryLookupStrategy} implementations that need access to an {@link EntityManager}.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -56,7 +58,7 @@ public final class JpaQueryLookupStrategy {
/**
* Creates a new {@link AbstractQueryLookupStrategy}.
*
*
* @param em
* @param extractor
* @param evaluationContextProvider
@@ -67,7 +69,7 @@ public final class JpaQueryLookupStrategy {
this.provider = extractor;
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries)
*/
@@ -82,7 +84,7 @@ public final class JpaQueryLookupStrategy {
/**
* {@link QueryLookupStrategy} to create a query from the method name.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -112,7 +114,7 @@ public final class JpaQueryLookupStrategy {
/**
* {@link QueryLookupStrategy} that tries to detect a declared query declared via {@link Query} annotation followed by
* a JPA named query lookup.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -122,7 +124,7 @@ public final class JpaQueryLookupStrategy {
/**
* Creates a new {@link DeclaredQueryLookupStrategy}.
*
*
* @param em
* @param extractor
* @param evaluationContextProvider
@@ -174,7 +176,7 @@ public final class JpaQueryLookupStrategy {
* {@link QueryLookupStrategy} to try to detect a declared query first (
* {@link org.springframework.data.jpa.repository.Query}, JPA named query). In case none is found we fall back on
* query creation.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -185,7 +187,7 @@ public final class JpaQueryLookupStrategy {
/**
* Creates a new {@link CreateIfNotFoundQueryLookupStrategy}.
*
*
* @param em
* @param extractor
* @param createStrategy
@@ -218,14 +220,14 @@ public final class JpaQueryLookupStrategy {
/**
* Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}.
*
*
* @param em must not be {@literal null}.
* @param key may be {@literal null}.
* @param extractor must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
* @return
*/
public static QueryLookupStrategy create(EntityManager em, Key key, QueryExtractor extractor,
public static QueryLookupStrategy create(EntityManager em, @Nullable Key key, QueryExtractor extractor,
EvaluationContextProvider evaluationContextProvider) {
Assert.notNull(em, "EntityManager must not be null!");

View File

@@ -41,6 +41,7 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -64,7 +65,7 @@ public class JpaQueryMethod extends QueryMethod {
static {
Set<Class<?>> types = new HashSet<Class<?>>();
Set<Class<?>> types = new HashSet<>();
types.add(byte[].class);
types.add(Byte[].class);
types.add(char[].class);
@@ -76,14 +77,15 @@ public class JpaQueryMethod extends QueryMethod {
private final QueryExtractor extractor;
private final Method method;
private StoredProcedureAttributes storedProcedureAttributes;
private @Nullable StoredProcedureAttributes storedProcedureAttributes;
/**
* Creates a {@link JpaQueryMethod}.
*
* @param method must not be {@literal null}
* @param extractor must not be {@literal null}
* @param metadata must not be {@literal null}
* @param factory must not be {@literal null}
* @param extractor must not be {@literal null}
*/
public JpaQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
QueryExtractor extractor) {
@@ -115,8 +117,9 @@ public class JpaQueryMethod extends QueryMethod {
continue;
}
if (!annotatedQuery.contains(String.format(":%s", parameter.getName().get()))
&& !annotatedQuery.contains(String.format("#%s", parameter.getName().get()))) {
if (StringUtils.isEmpty(annotatedQuery)
|| !annotatedQuery.contains(String.format(":%s", parameter.getName().get()))
&& !annotatedQuery.contains(String.format("#%s", parameter.getName().get()))) {
throw new IllegalStateException(
String.format("Using named parameters for method %s but parameter '%s' not found in annotated query '%s'!",
method, parameter.getName(), annotatedQuery));
@@ -152,7 +155,7 @@ public class JpaQueryMethod extends QueryMethod {
*/
List<QueryHint> getHints() {
List<QueryHint> result = new ArrayList<QueryHint>();
List<QueryHint> result = new ArrayList<>();
QueryHints hints = AnnotatedElementUtils.findMergedAnnotation(method, QueryHints.class);
if (hints != null) {
@@ -167,6 +170,7 @@ public class JpaQueryMethod extends QueryMethod {
*
* @return
*/
@Nullable
LockModeType getLockModeType() {
return (LockModeType) Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method, Lock.class)) //
@@ -180,6 +184,7 @@ public class JpaQueryMethod extends QueryMethod {
* @return
* @since 1.6
*/
@Nullable
JpaEntityGraph getEntityGraph() {
EntityGraph annotation = AnnotatedElementUtils.findMergedAnnotation(method, EntityGraph.class);
@@ -224,18 +229,39 @@ public class JpaQueryMethod extends QueryMethod {
*
* @return
*/
@Nullable
String getAnnotatedQuery() {
String query = getAnnotationValue("value", String.class);
return StringUtils.hasText(query) ? query : null;
}
/**
* Returns the required query string declared in a {@link Query} annotation or throws {@link IllegalStateException} if
* neither the annotation found nor the attribute was specified.
*
* @return
* @throws IllegalStateException if no {@link Query} annotation is present or the query is empty.
* @since 2.0
*/
String getRequiredAnnotatedQuery() throws IllegalStateException {
String query = getAnnotatedQuery();
if (query != null) {
return query;
}
throw new IllegalStateException(String.format("No annotated query found for query method %s!", getName()));
}
/**
* Returns the countQuery string declared in a {@link Query} annotation or {@literal null} if neither the annotation
* found nor the attribute was specified.
*
* @return
*/
@Nullable
String getCountQuery() {
String countQuery = getAnnotationValue("countQuery", String.class);
@@ -249,6 +275,7 @@ public class JpaQueryMethod extends QueryMethod {
* @return
* @since 1.6
*/
@Nullable
String getCountQueryProjection() {
String countProjection = getAnnotationValue("countProjection", String.class);

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014 the original author or authors.
* Copyright 2014-2017 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,12 +24,14 @@ import java.sql.SQLException;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.CleanupFailureDataAccessException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.lang.Nullable;
import org.springframework.util.StreamUtils;
/**
* Container for additional JPA result {@link Converter}s.
*
* @author Thomas Darimont
* @author Mark Paluch
* @since 1.6
*/
final class JpaResultConverters {
@@ -48,8 +50,9 @@ final class JpaResultConverters {
INSTANCE;
@Nullable
@Override
public byte[] convert(Blob source) {
public byte[] convert(@Nullable Blob source) {
if (source == null) {
return null;
@@ -67,9 +70,7 @@ final class JpaResultConverters {
return baos.toByteArray();
}
} catch (SQLException e) {
throw new DataRetrievalFailureException("Couldn't retrieve data from blob.", e);
} catch (IOException e) {
} catch (SQLException | IOException e) {
throw new DataRetrievalFailureException("Couldn't retrieve data from blob.", e);
} finally {
if (blobStream != null) {

View File

@@ -25,12 +25,14 @@ import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.lang.Nullable;
/**
* Implementation of {@link RepositoryQuery} based on {@link javax.persistence.NamedQuery}s.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
final class NamedQuery extends AbstractJpaQuery {
@@ -43,7 +45,7 @@ final class NamedQuery extends AbstractJpaQuery {
private final String queryName;
private final String countQueryName;
private final String countProjection;
private final @Nullable String countProjection;
private final QueryExtractor extractor;
private final boolean namedCountQueryIsPresent;
@@ -112,6 +114,7 @@ final class NamedQuery extends AbstractJpaQuery {
* @param method
* @return
*/
@Nullable
public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em) {
final String queryName = method.getNamedQueryName();
@@ -157,6 +160,11 @@ final class NamedQuery extends AbstractJpaQuery {
} else {
Query query = createQuery(values);
String queryString = extractor.extractQueryString(query);
if (queryString == null) {
throw new IllegalStateException(String.format("Cannot extract query string for query %s is null!", query));
}
countQuery = em.createQuery(QueryUtils.createCountQueryFor(queryString, countProjection), Long.class);
}

View File

@@ -63,7 +63,7 @@ public class ParameterBinder {
* Binds the parameters to the given query and applies special parameter types (e.g. pagination).
*
* @param query must not be {@literal null}.
* @param values values of method parameters to be assigned to the query parame
* @param values values of method parameters to be assigned to the query parameters.
*/
Query bindAndPrepare(Query query, Object[] values) {

View File

@@ -18,6 +18,7 @@ package org.springframework.data.jpa.repository.query;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.jpa.repository.query.ParameterMetadataProvider.ParameterMetadata;
@@ -25,6 +26,7 @@ import org.springframework.data.jpa.repository.query.StringQuery.ParameterBindin
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.util.StreamUtils;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -123,7 +125,7 @@ class ParameterBinderFactory {
return createSetters(null, parameterBindings, factories);
}
private static Iterable<QueryParameterSetter> createSetters(String queryString,
private static Iterable<QueryParameterSetter> createSetters(@Nullable String queryString,
List<ParameterBinding> parameterBindings, QueryParameterSetterFactory... strategies) {
return parameterBindings.stream() //
@@ -132,11 +134,11 @@ class ParameterBinderFactory {
}
private static QueryParameterSetter createQueryParameterSetter(ParameterBinding binding,
QueryParameterSetterFactory[] strategies, String queryString) {
QueryParameterSetterFactory[] strategies, @Nullable String queryString) {
return Arrays.stream(strategies)//
.map(it -> it.create(binding, queryString))//
.filter(it -> it != null)//
.filter(Objects::nonNull)//
.findFirst()//
.orElse(QueryParameterSetter.NOOP);
}

View File

@@ -32,6 +32,7 @@ import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.expression.Expression;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
@@ -49,7 +50,7 @@ class ParameterMetadataProvider {
private final CriteriaBuilder builder;
private final Iterator<? extends Parameter> parameters;
private final List<ParameterMetadata<?>> expressions;
private final Iterator<Object> bindableParameterValues;
private final @Nullable Iterator<Object> bindableParameterValues;
private final PersistenceProvider persistenceProvider;
/**
@@ -88,7 +89,7 @@ class ParameterMetadataProvider {
* @param parameters must not be {@literal null}.
* @param provider must not be {@literal null}.
*/
private ParameterMetadataProvider(CriteriaBuilder builder, Iterator<Object> bindableParameterValues,
private ParameterMetadataProvider(CriteriaBuilder builder, @Nullable Iterator<Object> bindableParameterValues,
Parameters<?, ?> parameters, PersistenceProvider provider) {
Assert.notNull(builder, "CriteriaBuilder must not be null!");
@@ -190,7 +191,8 @@ class ParameterMetadataProvider {
* @param value
* @param provider
*/
public ParameterMetadata(ParameterExpression<T> expression, Type type, Object value, PersistenceProvider provider) {
public ParameterMetadata(ParameterExpression<T> expression, Type type, @Nullable Object value,
PersistenceProvider provider) {
this.expression = expression;
this.persistenceProvider = provider;
@@ -221,6 +223,7 @@ class ParameterMetadataProvider {
* @param value must not be {@literal null}.
* @return
*/
@Nullable
public Object prepare(Object value) {
Assert.notNull(value, "Value must not be null!");
@@ -254,7 +257,8 @@ class ParameterMetadataProvider {
* @param value
* @return
*/
private static Collection<?> toCollection(Object value) {
@Nullable
private static Collection<?> toCollection(@Nullable Object value) {
if (value == null) {
return null;

View File

@@ -33,6 +33,7 @@ import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.lang.Nullable;
/**
* A {@link AbstractJpaQuery} implementation based on a {@link PartTree}.
@@ -41,6 +42,7 @@ import org.springframework.data.repository.query.parser.PartTree;
* @author Thomas Darimont
* @author Christoph Strobl
* @author Jens Schauder
* @author Mark Paluch
*/
public class PartTreeJpaQuery extends AbstractJpaQuery {
@@ -116,9 +118,9 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
*/
private class QueryPreparer {
private final CriteriaQuery<?> cachedCriteriaQuery;
private final ParameterBinder cachedParameterBinder;
private final List<ParameterMetadata<?>> expressions;
private final @Nullable CriteriaQuery<?> cachedCriteriaQuery;
private final @Nullable ParameterBinder cachedParameterBinder;
private final @Nullable List<ParameterMetadata<?>> expressions;
private final PersistenceProvider persistenceProvider;
QueryPreparer(PersistenceProvider persistenceProvider, boolean recreateQueries) {
@@ -156,6 +158,10 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
TypedQuery<?> jpaQuery = createQuery(criteriaQuery);
if (parameterBinder == null) {
throw new IllegalStateException("ParameterBinder is null!");
}
return restrictMaxResultsIfNecessary(invokeBinding(parameterBinder, jpaQuery, values));
}

View File

@@ -23,6 +23,7 @@ import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.criteria.ParameterExpression;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -30,6 +31,7 @@ import org.springframework.util.Assert;
* {@literal Query.setParameter}.
*
* @author Jens Schauder
* @author Mark Paluch
* @since 2.0
*/
interface QueryParameterSetter {
@@ -46,17 +48,17 @@ interface QueryParameterSetter {
private final Function<Object[], Object> valueExtractor;
private final Parameter<?> parameter;
private final TemporalType temporalType;
private final @Nullable TemporalType temporalType;
private final boolean lenient;
/**
* @param valueExtractor must not be {@literal null}.
* @param parameter must not be {@literal null}.
* @param temporalType must not be {@literal null}.
* @param temporalType may be {@literal null}.
* @param lenient must not be {@literal null}.
*/
NamedOrIndexedQueryParameterSetter(Function<Object[], Object> valueExtractor, Parameter<?> parameter,
TemporalType temporalType, boolean lenient) {
@Nullable TemporalType temporalType, boolean lenient) {
Assert.notNull(valueExtractor, "ValueExtractor must not be null!");

View File

@@ -31,6 +31,7 @@ import org.springframework.data.repository.query.Parameters;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -39,15 +40,17 @@ import org.springframework.util.Assert;
*
* @author Jens Schauder
* @author Oliver Gierke
* @author Mark Paluch
* @since 2.0
*/
abstract class QueryParameterSetterFactory {
abstract QueryParameterSetter create(ParameterBinding binding, String queryString);
@Nullable
abstract QueryParameterSetter create(ParameterBinding binding, @Nullable String queryString);
/**
* Creates a new {@link QueryParameterSetterFactory} for the given {@link JpaParameters}.
*
*
* @param parameters must not be {@literal null}.
* @return a basic {@link QueryParameterSetterFactory} that can handle named and index parameters.
*/
@@ -61,7 +64,7 @@ abstract class QueryParameterSetterFactory {
/**
* Creates a new {@link QueryParameterSetterFactory} using the given {@link JpaParameters} and
* {@link ParameterMetadata}.
*
*
* @param parameters must not be {@literal null}.
* @param metadata must not be {@literal null}.
* @return a {@link QueryParameterSetterFactory} for criteria Queries.
@@ -77,7 +80,7 @@ abstract class QueryParameterSetterFactory {
/**
* Creates a new {@link QueryParameterSetterFactory} for the given {@link SpelExpressionParser},
* {@link EvaluationContextProvider} and {@link Parameters}.
*
*
* @param parser must not be {@literal null}.
* @param evaluationContextProvider must not be {@literal null}.
* @param parameters must not be {@literal null}.
@@ -104,10 +107,10 @@ abstract class QueryParameterSetterFactory {
* @param lenient when true certain exceptions thrown when setting the query parameters get ignored.
*/
private static QueryParameterSetter createSetter(Function<Object[], Object> valueExtractor, ParameterBinding binding,
JpaParameter parameter, boolean lenient) {
@Nullable JpaParameter parameter, boolean lenient) {
TemporalType temporalType = parameter != null && parameter.isTemporalParameter() //
? parameter.getTemporalType() //
? parameter.getRequiredTemporalType() //
: null;
return new NamedOrIndexedQueryParameterSetter(valueExtractor.andThen(binding::prepare),
@@ -148,8 +151,9 @@ abstract class QueryParameterSetterFactory {
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.QueryParameterSetterFactory#create(org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding, java.lang.String)
*/
@Nullable
@Override
public QueryParameterSetter create(ParameterBinding binding, String queryString) {
public QueryParameterSetter create(ParameterBinding binding, @Nullable String queryString) {
if (!binding.isExpression()) {
return null;
@@ -162,11 +166,12 @@ abstract class QueryParameterSetterFactory {
/**
* Evaluates the given {@link Expression} against the given values.
*
*
* @param expression must not be {@literal null}.
* @param values must not be {@literal null}.
* @return the result of the evaluation.
*/
@Nullable
private Object evaluateExpression(Expression expression, Object[] values) {
EvaluationContext context = evaluationContextProvider.getEvaluationContext(parameters, values);
@@ -200,23 +205,24 @@ abstract class QueryParameterSetterFactory {
* @see org.springframework.data.jpa.repository.query.QueryParameterSetterFactory#create(org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding, java.lang.String)
*/
@Override
public QueryParameterSetter create(ParameterBinding binding, String queryString) {
public QueryParameterSetter create(ParameterBinding binding, @Nullable String queryString) {
Assert.notNull(binding, "Binding must not be null.");
JpaParameter parameter = QueryUtils.hasNamedParameter(queryString) //
? findParameterForBinding(binding) //
: parameters.getBindableParameter(binding.getPosition() - 1);
: parameters.getBindableParameter(binding.getRequiredPosition() - 1);
return parameter == null //
? QueryParameterSetter.NOOP //
: createSetter(values -> getValue(values, parameter), binding, parameter, false);
}
@Nullable
private JpaParameter findParameterForBinding(ParameterBinding binding) {
return parameters.getBindableParameters().stream() //
.filter(candidate -> binding.getName().equals(getName(candidate))) //
.filter(candidate -> binding.getRequiredName().equals(getName(candidate))) //
.findFirst().orElse(null);
}
@@ -231,7 +237,7 @@ abstract class QueryParameterSetterFactory {
/**
* {@link QueryParameterSetterFactory}
*
*
* @author Jens Schauder
* @author Oliver Gierke
*/
@@ -243,7 +249,7 @@ abstract class QueryParameterSetterFactory {
/**
* Creates a new {@link QueryParameterSetterFactory} from the given {@link JpaParameters} and
* {@link ParameterMetadata}.
*
*
* @param parameters must not be {@literal null}.
* @param metadata must not be {@literal null}.
*/
@@ -261,21 +267,22 @@ abstract class QueryParameterSetterFactory {
* @see org.springframework.data.jpa.repository.query.QueryParameterSetterFactory#create(org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding, java.lang.String)
*/
@Override
public QueryParameterSetter create(ParameterBinding binding, String queryString) {
public QueryParameterSetter create(ParameterBinding binding, @Nullable String queryString) {
ParameterMetadata<?> metadata = expressions.get(binding.getPosition() - 1);
ParameterMetadata<?> metadata = expressions.get(binding.getRequiredPosition() - 1);
if (metadata.isIsNullParameter()) {
return QueryParameterSetter.NOOP;
}
JpaParameter parameter = parameters.getBindableParameter(binding.getPosition() - 1);
TemporalType temporalType = parameter.isTemporalParameter() ? parameter.getTemporalType() : null;
JpaParameter parameter = parameters.getBindableParameter(binding.getRequiredPosition() - 1);
TemporalType temporalType = parameter.isTemporalParameter() ? parameter.getRequiredTemporalType() : null;
return new NamedOrIndexedQueryParameterSetter(values -> getAndPrepare(parameter, metadata, values),
metadata.getExpression(), temporalType, false);
}
@Nullable
private Object getAndPrepare(JpaParameter parameter, ParameterMetadata<?> metadata, Object[] values) {
JpaParametersParameterAccessor accessor = new JpaParametersParameterAccessor(parameters, values);
@@ -287,17 +294,17 @@ abstract class QueryParameterSetterFactory {
private static class ParameterImpl<T> implements javax.persistence.Parameter<T> {
private final Class<T> parameterType;
private final String name;
private final Integer position;
private final @Nullable String name;
private final @Nullable Integer position;
/**
* Creates a new {@link ParameterImpl} for the given {@link JpaParameter} and {@link ParameterBinding}.
*
*
* @param parameter can be {@literal null}.
* @param binding must not be {@literal null}.
* @return a {@link javax.persistence.Parameter} object based on the information from the arguments.
*/
static javax.persistence.Parameter<?> of(JpaParameter parameter, ParameterBinding binding) {
static javax.persistence.Parameter<?> of(@Nullable JpaParameter parameter, ParameterBinding binding) {
Class<?> type = parameter == null ? Object.class : parameter.getType();
@@ -306,37 +313,39 @@ abstract class QueryParameterSetterFactory {
/**
* Creates a new {@link ParameterImpl} for the given name, position and parameter type.
*
*
* @param parameterType must not be {@literal null}.
* @param name can be {@literal null}.
* @param position can be {@literal null}.
*/
private ParameterImpl(Class<T> parameterType, String name, Integer position) {
private ParameterImpl(Class<T> parameterType, @Nullable String name, @Nullable Integer position) {
this.name = name;
this.position = position;
this.parameterType = parameterType;
}
/*
/*
* (non-Javadoc)
* @see javax.persistence.Parameter#getName()
*/
@Nullable
@Override
public String getName() {
return name;
}
/*
/*
* (non-Javadoc)
* @see javax.persistence.Parameter#getPosition()
*/
@Nullable
@Override
public Integer getPosition() {
return position;
}
/*
/*
* (non-Javadoc)
* @see javax.persistence.Parameter#getParameterType()
*/
@@ -345,7 +354,8 @@ abstract class QueryParameterSetterFactory {
return parameterType;
}
private static String getName(JpaParameter parameter, ParameterBinding binding) {
@Nullable
private static String getName(@Nullable JpaParameter parameter, ParameterBinding binding) {
if (parameter == null) {
return binding.getName();

View File

@@ -57,6 +57,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.jpa.domain.JpaSort.JpaOrder;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -224,14 +225,14 @@ public abstract class QueryUtils {
*
* @param query the query string to which sorting is applied. Must not be {@literal null} or empty.
* @param sort the sort specification to apply.
* @param alias the alias to be used in the order by clause. Must not be {@literal null} or empty.
* @param alias the alias to be used in the order by clause. May be {@literal null} or empty.
* @return the modified query string.
*/
public static String applySorting(String query, Sort sort, String alias) {
public static String applySorting(String query, Sort sort, @Nullable String alias) {
Assert.hasText(query, "Query must not be null or empty!");
if (null == sort || !sort.iterator().hasNext()) {
if (sort.isUnsorted()) {
return query;
}
@@ -264,7 +265,8 @@ public abstract class QueryUtils {
* @param order the order object to build the clause for.
* @return
*/
private static String getOrderClause(Set<String> joinAliases, Set<String> functionAlias, String alias, Order order) {
private static String getOrderClause(Set<String> joinAliases, Set<String> functionAlias, @Nullable String alias,
Order order) {
String property = order.getProperty();
@@ -345,6 +347,7 @@ public abstract class QueryUtils {
* @param query
* @return
*/
@Nullable
public static String detectAlias(String query) {
Matcher matcher = ALIAS_MATCH.matcher(query);
@@ -421,7 +424,7 @@ public abstract class QueryUtils {
* @return
* @since 1.6
*/
public static String createCountQueryFor(String originalQuery, String countProjection) {
public static String createCountQueryFor(String originalQuery, @Nullable String countProjection) {
Assert.hasText(originalQuery, "OriginalQuery must not be null or empty!");
@@ -472,7 +475,7 @@ public abstract class QueryUtils {
* @param query can be {@literal null} or empty.
* @return
*/
public static boolean hasNamedParameter(String query) {
public static boolean hasNamedParameter(@Nullable String query) {
return StringUtils.hasText(query) && NAMED_PARAMETER.matcher(query).find();
}
@@ -488,7 +491,7 @@ public abstract class QueryUtils {
List<javax.persistence.criteria.Order> orders = new ArrayList<javax.persistence.criteria.Order>();
if (sort == null) {
if (sort.isUnsorted()) {
return orders;
}
@@ -556,7 +559,7 @@ public abstract class QueryUtils {
@SuppressWarnings("unchecked")
static <T> Expression<T> toExpressionRecursively(From<?, ?> from, PropertyPath property) {
Bindable<?> propertyPathModel = null;
Bindable<?> propertyPathModel;
Bindable<?> model = from.getModel();
String segment = property.getSegment();
@@ -584,11 +587,11 @@ public abstract class QueryUtils {
* Returns whether the given {@code propertyPathModel} requires the creation of a join. This is the case if we find a
* non-optional association.
*
* @param propertyPathModel must not be {@literal null}.
* @param propertyPathModel may be {@literal null}.
* @param forPluralAttribute
* @return
*/
private static boolean requiresJoin(Bindable<?> propertyPathModel, boolean forPluralAttribute) {
private static boolean requiresJoin(@Nullable Bindable<?> propertyPathModel, boolean forPluralAttribute) {
if (propertyPathModel == null && forPluralAttribute) {
return true;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2013 the original author or authors.
* Copyright 2008-2017 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.
@@ -29,6 +29,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
@@ -42,7 +43,7 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
*/
public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, EvaluationContextProvider evaluationContextProvider,
SpelExpressionParser parser) {
this(method, em, method.getAnnotatedQuery(), evaluationContextProvider, parser);
this(method, em, method.getRequiredAnnotatedQuery(), evaluationContextProvider, parser);
}
/**
@@ -73,7 +74,7 @@ final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
* @param query
* @param em
*/
private final void validateQuery(String query, String errorMessage) {
private void validateQuery(String query, String errorMessage) {
if (getQueryMethod().isProcedureQuery()) {
return;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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,6 +25,7 @@ import javax.persistence.NamedStoredProcedureQuery;
import javax.persistence.StoredProcedureParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -34,6 +35,7 @@ import org.springframework.util.StringUtils;
* @author Thomas Darimont
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
* @since 1.6
*/
enum StoredProcedureAttributeSource {
@@ -157,6 +159,7 @@ enum StoredProcedureAttributeSource {
* @param procedure must not be {@literal null}.
* @return
*/
@Nullable
private NamedStoredProcedureQuery tryFindAnnotatedNamedStoredProcedureQuery(Method method,
JpaEntityMetadata<?> entityMetadata, Procedure procedure) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2015 the original author or authors.
* Copyright 2014-2017 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.StoredProcedureQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -25,6 +26,7 @@ import org.springframework.util.StringUtils;
*
* @author Thomas Darimont
* @author Oliver Gierke
* @author Mark Paluch
* @since 1.6
*/
class StoredProcedureAttributes {
@@ -45,8 +47,8 @@ class StoredProcedureAttributes {
* @param outputParameterIndex must not be {@literal null}
* @param outputParameterType
*/
public StoredProcedureAttributes(String procedureName, String outputParameterName, Class<?> outputParameterType,
boolean namedStoredProcedure) {
public StoredProcedureAttributes(String procedureName, @Nullable String outputParameterName,
Class<?> outputParameterType, boolean namedStoredProcedure) {
Assert.notNull(procedureName, "ProcedureName must not be null!");
Assert.notNull(outputParameterType, "OutputParameterType must not be null!");

View File

@@ -24,6 +24,7 @@ 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.QueryMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -35,6 +36,7 @@ import org.springframework.util.StringUtils;
* @author Oliver Gierke
* @author Christoph Strobl
* @author Jens Schauder
* @author Mark Paluch
* @since 1.6
*/
class StoredProcedureJpaQuery extends AbstractJpaQuery {
@@ -96,7 +98,7 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
*/
@Override
protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
return null;
throw new UnsupportedOperationException("StoredProcedureQuery does not support count queries!");
}
/**
@@ -104,6 +106,7 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
*
* @param storedProcedureQuery must not be {@literal null}.
*/
@Nullable
Object extractOutputValue(StoredProcedureQuery storedProcedureQuery) {
Assert.notNull(storedProcedureQuery, "StoredProcedureQuery must not be null!");

View File

@@ -27,6 +27,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.data.repository.query.parser.Part.Type;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -47,7 +48,7 @@ class StringQuery {
private final String query;
private final List<ParameterBinding> bindings;
private final String alias;
private final @Nullable String alias;
private final boolean hasConstructorExpression;
/**
@@ -83,7 +84,7 @@ class StringQuery {
/**
* Returns the query string.
*/
public String getQueryString() {
String getQueryString() {
return query;
}
@@ -92,6 +93,7 @@ class StringQuery {
*
* @return the alias
*/
@Nullable
String getAlias() {
return alias;
}
@@ -287,9 +289,9 @@ class StringQuery {
// character, while = does not.
LIKE("like "), IN("in "), AS_IS(null);
private final String keyword;
private final @Nullable String keyword;
ParameterBindingType(String keyword) {
ParameterBindingType(@Nullable String keyword) {
this.keyword = keyword;
}
@@ -299,6 +301,7 @@ class StringQuery {
*
* @return the keyword
*/
@Nullable
public String getKeyword() {
return keyword;
}
@@ -331,9 +334,9 @@ class StringQuery {
*/
static class ParameterBinding {
private final String name;
private final String expression;
private final Integer position;
private final @Nullable String name;
private final @Nullable String expression;
private final @Nullable Integer position;
/**
* Creates a new {@link ParameterBinding} for the parameter with the given position.
@@ -352,7 +355,7 @@ class StringQuery {
* @param position of the parameter may be {@literal null}.
* @param expression the expression to apply to any value for this parameter.
*/
ParameterBinding(String name, Integer position, String expression) {
ParameterBinding(@Nullable String name, @Nullable Integer position, @Nullable String expression) {
if (name == null) {
Assert.notNull(position, "Position must not be null!");
@@ -371,7 +374,7 @@ class StringQuery {
* Returns whether the binding has the given name. Will always be {@literal false} in case the
* {@link ParameterBinding} has been set up from a position.
*/
boolean hasName(String name) {
boolean hasName(@Nullable String name) {
return this.position == null && this.name != null && this.name.equals(name);
}
@@ -379,24 +382,58 @@ class StringQuery {
* Returns whether the binding has the given position. Will always be {@literal false} in case the
* {@link ParameterBinding} has been set up from a name.
*/
boolean hasPosition(Integer position) {
boolean hasPosition(@Nullable Integer position) {
return position != null && this.name == null && position.equals(this.position);
}
/**
* @return the name
*/
@Nullable
public String getName() {
return name;
}
/**
* @return the name
* @throws IllegalStateException if the name is not available.
* @since 2.0
*/
String getRequiredName() throws IllegalStateException {
String name = getName();
if (name != null) {
return name;
}
throw new IllegalStateException(String.format("Required name for %s not available!", this));
}
/**
* @return the position
*/
@Nullable
Integer getPosition() {
return position;
}
/**
* @return the position
* @throws IllegalStateException if the position is not available.
* @since 2.0
*/
int getRequiredPosition() throws IllegalStateException {
Integer position = getPosition();
if (position != null) {
return position;
}
throw new IllegalStateException(String.format("Required position for %s not available!", this));
}
/**
* @return {@literal true} if this parameter binding is a synthetic SpEL expression.
*/
@@ -450,10 +487,12 @@ class StringQuery {
/**
* @param valueToBind value to prepare
*/
public Object prepare(Object valueToBind) {
@Nullable
public Object prepare(@Nullable Object valueToBind) {
return valueToBind;
}
@Nullable
public String getExpression() {
return expression;
}
@@ -470,14 +509,14 @@ class StringQuery {
/**
* Creates a new {@link InParameterBinding} for the parameter with the given name.
*/
InParameterBinding(String name, String expression) {
InParameterBinding(String name, @Nullable String expression) {
super(name, null, expression);
}
/**
* Creates a new {@link InParameterBinding} for the parameter with the given position.
*/
InParameterBinding(int position, String expression) {
InParameterBinding(int position, @Nullable String expression) {
super(null, position, expression);
}
@@ -486,7 +525,7 @@ class StringQuery {
* @see org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding#prepare(java.lang.Object)
*/
@Override
public Object prepare(Object value) {
public Object prepare(@Nullable Object value) {
if (!ObjectUtils.isArray(value)) {
return value;
@@ -535,7 +574,7 @@ class StringQuery {
* @param type must not be {@literal null}.
* @param expression may be {@literal null}.
*/
LikeParameterBinding(String name, Type type, String expression) {
LikeParameterBinding(String name, Type type, @Nullable String expression) {
super(name, null, expression);
@@ -565,7 +604,7 @@ class StringQuery {
* @param type must not be {@literal null}.
* @param expression may be {@literal null}.
*/
LikeParameterBinding(int position, Type type, String expression) {
LikeParameterBinding(int position, Type type, @Nullable String expression) {
super(null, position, expression);
@@ -592,8 +631,9 @@ class StringQuery {
*
* @param keyword
*/
@Nullable
@Override
public Object prepare(Object value) {
public Object prepare(@Nullable Object value) {
if (value == null) {
return null;

View File

@@ -1,5 +1,7 @@
/**
* Query implementation to exectue queries against JPA.
*/
@NonNullApi
package org.springframework.data.jpa.repository.query;
import org.springframework.lang.NonNullApi;

View File

@@ -22,6 +22,7 @@ import java.util.Optional;
import javax.persistence.LockModeType;
import org.springframework.data.jpa.repository.EntityGraph;
import org.springframework.lang.Nullable;
/**
* Interface to abstract {@link CrudMethodMetadata} that provide the {@link LockModeType} to be used for query
@@ -30,6 +31,7 @@ import org.springframework.data.jpa.repository.EntityGraph;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
public interface CrudMethodMetadata {
@@ -38,6 +40,7 @@ public interface CrudMethodMetadata {
*
* @return
*/
@Nullable
LockModeType getLockModeType();
/**

View File

@@ -39,6 +39,7 @@ import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.QueryHints;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.lang.Nullable;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -51,10 +52,11 @@ import org.springframework.util.ClassUtils;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Christoph Strobl
* @author Mark Paluch
*/
class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, BeanClassLoaderAware {
private ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
private @Nullable ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
/*
* (non-Javadoc)
@@ -62,8 +64,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader == null ? ClassUtils.getDefaultClassLoader() : classLoader;
this.classLoader = classLoader;
}
/*
@@ -97,7 +98,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
* @author Oliver Gierke
* @author Thomas Darimont
*/
static enum CrudMethodMetadataPopulatingMethodInterceptor implements MethodInterceptor {
enum CrudMethodMetadataPopulatingMethodInterceptor implements MethodInterceptor {
INSTANCE;
@@ -146,7 +147,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
*/
private static class DefaultCrudMethodMetadata implements CrudMethodMetadata {
private final LockModeType lockModeType;
private final @Nullable LockModeType lockModeType;
private final Map<String, Object> queryHints;
private final Optional<EntityGraph> entityGraph;
private final Method method;
@@ -156,7 +157,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
*
* @param method must not be {@literal null}.
*/
public DefaultCrudMethodMetadata(Method method) {
DefaultCrudMethodMetadata(Method method) {
Assert.notNull(method, "Method must not be null!");
@@ -170,6 +171,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
return Optional.ofNullable(AnnotatedElementUtils.findMergedAnnotation(method, EntityGraph.class));
}
@Nullable
private static LockModeType findLockModeType(Method method) {
Lock annotation = AnnotatedElementUtils.findMergedAnnotation(method, Lock.class);
@@ -201,6 +203,7 @@ class CrudMethodMetadataPostProcessor implements RepositoryProxyPostProcessor, B
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.CrudMethodMetadata#getLockModeType()
*/
@Nullable
@Override
public LockModeType getLockModeType() {
return lockModeType;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2014 the original author or authors.
* Copyright 2011-2017 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.
@@ -19,12 +19,14 @@ import javax.persistence.metamodel.SingularAttribute;
import org.springframework.data.jpa.repository.query.JpaEntityMetadata;
import org.springframework.data.repository.core.EntityInformation;
import org.springframework.lang.Nullable;
/**
* Extension of {@link EntityInformation} to capture additional JPA specific information about entities.
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public interface JpaEntityInformation<T, ID> extends EntityInformation<T, ID>, JpaEntityMetadata<T> {
@@ -33,8 +35,28 @@ public interface JpaEntityInformation<T, ID> extends EntityInformation<T, ID>, J
*
* @return
*/
@Nullable
SingularAttribute<? super T, ?> getIdAttribute();
/**
* Returns the required identifier type.
*
* @return the identifier type.
* @throws IllegalArgumentException in case no id type could be obtained.
* @since 2.0
*/
default SingularAttribute<? super T, ?> getRequiredIdAttribute() throws IllegalArgumentException {
SingularAttribute<? super T, ?> id = getIdAttribute();
if (id != null) {
return id;
}
throw new IllegalArgumentException(
String.format("Could not obtain required identifier attribute for type %s!", getEntityName()));
}
/**
* Returns {@literal true} if the entity has a composite id.
*
@@ -57,5 +79,6 @@ public interface JpaEntityInformation<T, ID> extends EntityInformation<T, ID>, J
* @param idAttribute
* @return
*/
@Nullable
Object getCompositeIdAttributeValue(Object id, String idAttribute);
}

View File

@@ -19,9 +19,11 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import javax.persistence.IdClass;
import javax.persistence.metamodel.Attribute;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.ManagedType;
@@ -34,6 +36,7 @@ import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -49,9 +52,9 @@ import org.springframework.util.ClassUtils;
public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSupport<T, ID> {
private final IdMetadata<T> idMetadata;
private final SingularAttribute<? super T, ?> versionAttribute;
private final Optional<SingularAttribute<? super T, ?>> versionAttribute;
private final Metamodel metamodel;
private final String entityName;
private final @Nullable String entityName;
/**
* Creates a new {@link JpaMetamodelEntityInformation} for the given domain class and {@link Metamodel}.
@@ -101,11 +104,11 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
* @return
*/
@SuppressWarnings("unchecked")
private static <T> SingularAttribute<? super T, ?> findVersionAttribute(IdentifiableType<T> type,
private static <T> Optional<SingularAttribute<? super T, ?>> findVersionAttribute(IdentifiableType<T> type,
Metamodel metamodel) {
try {
return type.getVersion(Object.class);
return Optional.ofNullable(type.getVersion(Object.class));
} catch (IllegalArgumentException o_O) {
// Needs workarounds as the method is implemented with a strict type check on e.g. Hibernate < 4.3
}
@@ -114,7 +117,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
for (SingularAttribute<? super T, ?> attribute : attributes) {
if (attribute.isVersion()) {
return attribute;
return Optional.of(attribute);
}
}
@@ -125,13 +128,13 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
ManagedType<?> managedSuperType = metamodel.managedType(superType);
if (!(managedSuperType instanceof IdentifiableType)) {
return null;
return Optional.empty();
}
return (SingularAttribute<? super T, ?>) findVersionAttribute((IdentifiableType<T>) managedSuperType, metamodel);
return findVersionAttribute((IdentifiableType<T>) managedSuperType, metamodel);
} catch (IllegalArgumentException o_O) {
return null;
return Optional.empty();
}
}
@@ -139,6 +142,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
* (non-Javadoc)
* @see org.springframework.data.repository.core.EntityInformation#getId(java.lang.Object)
*/
@Nullable
@SuppressWarnings("unchecked")
public ID getId(T entity) {
@@ -222,14 +226,14 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
@Override
public boolean isNew(T entity) {
if (versionAttribute == null || versionAttribute.getJavaType().isPrimitive()) {
if (!versionAttribute.isPresent()
|| versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {
return super.isNew(entity);
}
BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);
Object versionValue = wrapper.getPropertyValue(versionAttribute.getName());
return versionValue == null;
return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);
}
/**
@@ -242,14 +246,15 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
private final IdentifiableType<T> type;
private final Set<SingularAttribute<? super T, ?>> attributes;
private Class<?> idType;
private @Nullable Class<?> idType;
@SuppressWarnings("unchecked")
public IdMetadata(IdentifiableType<T> source) {
this.type = source;
this.attributes = (Set<SingularAttribute<? super T, ?>>) (source.hasSingleIdAttribute()
? Collections.singleton(source.getId(source.getIdType().getJavaType())) : source.getIdClassAttributes());
? Collections.singleton(source.getId(source.getIdType().getJavaType()))
: source.getIdClassAttributes());
}
public boolean hasSimpleId() {
@@ -265,9 +270,14 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
// lazy initialization of idType field with tolerable benign data-race
this.idType = tryExtractIdTypeWithFallbackToIdTypeLookup();
if (this.idType == null) {
throw new IllegalStateException("Cannot resolve Id type from " + type);
}
return this.idType;
}
@Nullable
private Class<?> tryExtractIdTypeWithFallbackToIdTypeLookup() {
try {
@@ -279,6 +289,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
}
}
@Nullable
private static Class<?> fallbackIdTypeLookup(IdentifiableType<?> type) {
IdClass annotation = AnnotationUtils.findAnnotation(type.getJavaType(), IdClass.class);
@@ -309,7 +320,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
private final Metamodel metamodel;
public IdentifierDerivingDirectFieldAccessFallbackBeanWrapper(Class<?> type, Metamodel metamodel) {
IdentifierDerivingDirectFieldAccessFallbackBeanWrapper(Class<?> type, Metamodel metamodel) {
super(type);
this.metamodel = metamodel;
}
@@ -320,7 +331,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
*/
@Override
@SuppressWarnings("unchecked")
public void setPropertyValue(String propertyName, Object value) {
public void setPropertyValue(String propertyName, @Nullable Object value) {
if (!isIdentifierDerivationNecessary(value)) {
super.setPropertyValue(propertyName, value);
@@ -335,7 +346,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
if (!nestedEntityInformation.getJavaType().isAnnotationPresent(IdClass.class)) {
Object nestedIdPropertyValue = new DirectFieldAccessFallbackBeanWrapper(value)
.getPropertyValue(nestedEntityInformation.getIdAttribute().getName());
.getPropertyValue(nestedEntityInformation.getRequiredIdAttribute().getName());
super.setPropertyValue(propertyName, nestedIdPropertyValue);
return;
}
@@ -354,6 +365,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
super.setPropertyValue(propertyName, targetIdClassTypeWrapper.getWrappedInstance());
}
@Nullable
private Object extractActualIdPropertyValue(BeanWrapper sourceIdValueWrapper, String idAttributeName) {
Object idPropertyValue = sourceIdValueWrapper.getPropertyValue(idAttributeName);
@@ -391,7 +403,7 @@ public class JpaMetamodelEntityInformation<T, ID> extends JpaEntityInformationSu
* @return {@literal true} if the given value is not {@literal null} and a mapped persistable entity otherwise
* {@literal false}
*/
private boolean isIdentifierDerivationNecessary(Object value) {
private boolean isIdentifierDerivationNecessary(@Nullable Object value) {
if (value == null) {
return false;

View File

@@ -18,12 +18,14 @@ package org.springframework.data.jpa.repository.support;
import javax.persistence.metamodel.Metamodel;
import org.springframework.data.domain.Persistable;
import org.springframework.lang.Nullable;
/**
* Extension of {@link JpaMetamodelEntityInformation} that consideres methods of {@link Persistable} to lookup the id.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
*/
public class JpaPersistableEntityInformation<T extends Persistable<ID>, ID>
extends JpaMetamodelEntityInformation<T, ID> {
@@ -51,6 +53,7 @@ public class JpaPersistableEntityInformation<T extends Persistable<ID>, ID>
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.support.JpaMetamodelEntityInformation#getId(java.lang.Object)
*/
@Nullable
@Override
public ID getId(T entity) {
return entity.getId();

View File

@@ -33,6 +33,7 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -133,7 +134,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getQueryLookupStrategy(org.springframework.data.repository.query.QueryLookupStrategy.Key, org.springframework.data.repository.query.EvaluationContextProvider)
*/
@Override
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(Key key,
protected Optional<QueryLookupStrategy> getQueryLookupStrategy(@Nullable Key key,
EvaluationContextProvider evaluationContextProvider) {
return Optional.of(JpaQueryLookupStrategy.create(entityManager, key, extractor, evaluationContextProvider));
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2014 the original author or authors.
* Copyright 2008-2017 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.
@@ -22,6 +22,7 @@ import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -30,12 +31,13 @@ import org.springframework.util.Assert;
*
* @author Oliver Gierke
* @author Eberhard Wolff
* @author Mark Paluch
* @param <T> the type of the repository
*/
public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {
private EntityManager entityManager;
private @Nullable EntityManager entityManager;
/**
* Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
@@ -73,6 +75,11 @@ public class JpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
*/
@Override
protected RepositoryFactorySupport doCreateRepositoryFactory() {
if (entityManager == null) {
throw new IllegalStateException("EntityManager must not be null!");
}
return createRepositoryFactory(entityManager);
}

View File

@@ -125,7 +125,7 @@ public class Querydsl {
*/
public <T> JPQLQuery<T> applySorting(Sort sort, JPQLQuery<T> query) {
if (sort == null) {
if (sort.isUnsorted()) {
return query;
}

View File

@@ -32,6 +32,7 @@ import org.springframework.data.querydsl.QSort;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import com.querydsl.core.NonUniqueResultException;
@@ -160,7 +161,7 @@ public class QuerydslJpaRepository<T, ID extends Serializable> extends SimpleJpa
final JPQLQuery<?> countQuery = createCountQuery(predicate);
JPQLQuery<T> query = querydsl.applyPagination(pageable, createQuery(predicate).select(path));
return PageableExecutionUtils.getPage(query.fetch(), pageable, () -> countQuery.fetchCount());
return PageableExecutionUtils.getPage(query.fetch(), pageable, countQuery::fetchCount);
}
/*
@@ -207,13 +208,17 @@ public class QuerydslJpaRepository<T, ID extends Serializable> extends SimpleJpa
* @param predicate, can be {@literal null}.
* @return the Querydsl count {@link JPQLQuery}.
*/
protected JPQLQuery<?> createCountQuery(Predicate... predicate) {
protected JPQLQuery<?> createCountQuery(@Nullable Predicate... predicate) {
return doCreateQuery(getQueryHints(), predicate);
}
private AbstractJPAQuery<?, ?> doCreateQuery(QueryHints hints, Predicate... predicate) {
private AbstractJPAQuery<?, ?> doCreateQuery(QueryHints hints, @Nullable Predicate... predicate) {
AbstractJPAQuery<?, ?> query = querydsl.createQuery(path).where(predicate);
AbstractJPAQuery<?, ?> query = querydsl.createQuery(path);
if (predicate != null) {
query = query.where(predicate);
}
for (Entry<String, Object> hint : hints) {
query.setHint(hint.getKey(), hint.getValue());

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.data.jpa.repository.support;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
@@ -42,8 +43,8 @@ public abstract class QuerydslRepositorySupport {
private final PathBuilder<?> builder;
private EntityManager entityManager;
private Querydsl querydsl;
private @Nullable EntityManager entityManager;
private @Nullable Querydsl querydsl;
/**
* Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
@@ -83,6 +84,7 @@ public abstract class QuerydslRepositorySupport {
*
* @return the entityManager
*/
@Nullable
protected EntityManager getEntityManager() {
return entityManager;
}
@@ -94,7 +96,7 @@ public abstract class QuerydslRepositorySupport {
* @return the Querydsl {@link JPQLQuery}.
*/
protected JPQLQuery<Object> from(EntityPath<?>... paths) {
return querydsl.createQuery(paths);
return getRequiredQuerydsl().createQuery(paths);
}
/**
@@ -104,7 +106,7 @@ public abstract class QuerydslRepositorySupport {
* @return
*/
protected <T> JPQLQuery<T> from(EntityPath<T> path) {
return querydsl.createQuery(path).select(path);
return getRequiredQuerydsl().createQuery(path).select(path);
}
/**
@@ -114,7 +116,7 @@ public abstract class QuerydslRepositorySupport {
* @return the Querydsl {@link DeleteClause}.
*/
protected DeleteClause<JPADeleteClause> delete(EntityPath<?> path) {
return new JPADeleteClause(entityManager, path);
return new JPADeleteClause(getRequiredEntityManager(), path);
}
/**
@@ -124,7 +126,7 @@ public abstract class QuerydslRepositorySupport {
* @return the Querydsl {@link UpdateClause}.
*/
protected UpdateClause<JPAUpdateClause> update(EntityPath<?> path) {
return new JPAUpdateClause(entityManager, path);
return new JPAUpdateClause(getRequiredEntityManager(), path);
}
/**
@@ -143,7 +145,26 @@ public abstract class QuerydslRepositorySupport {
*
* @return
*/
@Nullable
protected Querydsl getQuerydsl() {
return this.querydsl;
}
private Querydsl getRequiredQuerydsl() {
if (querydsl == null) {
throw new IllegalStateException("Querydsl is null!");
}
return querydsl;
}
private EntityManager getRequiredEntityManager() {
if (entityManager == null) {
throw new IllegalStateException("EntityManager is null!");
}
return entityManager;
}
}

View File

@@ -53,6 +53,7 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
@@ -79,7 +80,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
private final EntityManager em;
private final PersistenceProvider provider;
private CrudMethodMetadata metadata;
private @Nullable CrudMethodMetadata metadata;
/**
* Creates a new {@link SimpleJpaRepository} to manage objects of the given {@link JpaEntityInformation}.
@@ -117,7 +118,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
this.metadata = crudMethodMetadata;
}
protected CrudMethodMetadata getRepositoryMethodMetadata() {
protected @Nullable CrudMethodMetadata getRepositoryMethodMetadata() {
return metadata;
}
@@ -301,7 +302,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* @see org.springframework.data.jpa.repository.JpaRepository#findAll()
*/
public List<T> findAll() {
return getQuery(null, (Sort) null).getResultList();
return getQuery(null, Sort.unsorted()).getResultList();
}
/*
@@ -310,7 +311,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*/
public List<T> findAllById(Iterable<ID> ids) {
if (ids == null || !ids.iterator().hasNext()) {
Assert.notNull(ids, "The given Iterable of Id's must not be null!");
if (!ids.iterator().hasNext()) {
return Collections.emptyList();
}
@@ -326,7 +329,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
}
ByIdsSpecification<T> specification = new ByIdsSpecification<T>(entityInformation);
TypedQuery<T> query = getQuery(specification, (Sort) null);
TypedQuery<T> query = getQuery(specification, Sort.unsorted());
return query.setParameter(specification.parameter, ids).getResultList();
}
@@ -356,10 +359,10 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findOne(org.springframework.data.jpa.domain.Specification)
*/
public Optional<T> findOne(Specification<T> spec) {
public Optional<T> findOne(@Nullable Specification<T> spec) {
try {
return Optional.of(getQuery(spec, (Sort) null).getSingleResult());
return Optional.of(getQuery(spec, Sort.unsorted()).getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
@@ -369,15 +372,15 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification)
*/
public List<T> findAll(Specification<T> spec) {
return getQuery(spec, (Sort) null).getResultList();
public List<T> findAll(@Nullable Specification<T> spec) {
return getQuery(spec, Sort.unsorted()).getResultList();
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification, org.springframework.data.domain.Pageable)
*/
public Page<T> findAll(Specification<T> spec, Pageable pageable) {
public Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable) {
TypedQuery<T> query = getQuery(spec, pageable);
return isUnpaged(pageable) ? new PageImpl<T>(query.getResultList())
@@ -388,7 +391,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#findAll(org.springframework.data.jpa.domain.Specification, org.springframework.data.domain.Sort)
*/
public List<T> findAll(Specification<T> spec, Sort sort) {
public List<T> findAll(@Nullable Specification<T> spec, Sort sort) {
return getQuery(spec, sort).getResultList();
}
@@ -401,7 +404,8 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
try {
return Optional
.of(getQuery(new ExampleSpecification<S>(example), example.getProbeType(), (Sort) null).getSingleResult());
.of(getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted())
.getSingleResult());
} catch (NoResultException e) {
return Optional.empty();
}
@@ -422,7 +426,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*/
@Override
public <S extends T> boolean exists(Example<S> example) {
return !getQuery(new ExampleSpecification<S>(example), example.getProbeType(), (Sort) null).getResultList()
return !getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted()).getResultList()
.isEmpty();
}
@@ -432,7 +436,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*/
@Override
public <S extends T> List<S> findAll(Example<S> example) {
return getQuery(new ExampleSpecification<S>(example), example.getProbeType(), (Sort) null).getResultList();
return getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted()).getResultList();
}
/*
@@ -470,7 +474,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.JpaSpecificationExecutor#count(org.springframework.data.jpa.domain.Specification)
*/
public long count(Specification<T> spec) {
public long count(@Nullable Specification<T> spec) {
return executeCountQuery(getCountQuery(spec, getDomainClass()));
}
@@ -509,11 +513,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
@Transactional
public <S extends T> List<S> saveAll(Iterable<S> entities) {
List<S> result = new ArrayList<S>();
Assert.notNull(entities, "The given Iterable of entities not be null!");
if (entities == null) {
return result;
}
List<S> result = new ArrayList<S>();
for (S entity : entities) {
result.add(save(entity));
@@ -537,12 +539,12 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*
* @param query must not be {@literal null}.
* @param spec can be {@literal null}.
* @param pageable can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return
* @deprecated use {@link #readPage(TypedQuery, Class, Pageable, Specification)} instead
*/
@Deprecated
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, @Nullable Specification<T> spec) {
return readPage(query, getDomainClass(), pageable, spec);
}
@@ -557,7 +559,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* @return
*/
protected <S extends T> Page<S> readPage(TypedQuery<S> query, final Class<S> domainClass, Pageable pageable,
final Specification<S> spec) {
@Nullable Specification<S> spec) {
if (pageable.isPaged()) {
query.setFirstResult((int) pageable.getOffset());
@@ -572,12 +574,12 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* Creates a new {@link TypedQuery} from the given {@link Specification}.
*
* @param spec can be {@literal null}.
* @param pageable can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return
*/
protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {
protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Pageable pageable) {
Sort sort = pageable == null ? null : pageable.getSort();
Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
return getQuery(spec, getDomainClass(), sort);
}
@@ -586,12 +588,13 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*
* @param spec can be {@literal null}.
* @param domainClass must not be {@literal null}.
* @param pageable can be {@literal null}.
* @param pageable must not be {@literal null}.
* @return
*/
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Pageable pageable) {
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass,
Pageable pageable) {
Sort sort = pageable == null ? null : pageable.getSort();
Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();
return getQuery(spec, domainClass, sort);
}
@@ -599,10 +602,10 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}.
*
* @param spec can be {@literal null}.
* @param sort can be {@literal null}.
* @param sort must not be {@literal null}.
* @return
*/
protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
protected TypedQuery<T> getQuery(@Nullable Specification<T> spec, Sort sort) {
return getQuery(spec, getDomainClass(), sort);
}
@@ -611,10 +614,10 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*
* @param spec can be {@literal null}.
* @param domainClass must not be {@literal null}.
* @param sort can be {@literal null}.
* @param sort must not be {@literal null}.
* @return
*/
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {
protected <S extends T> TypedQuery<S> getQuery(@Nullable Specification<S> spec, Class<S> domainClass, Sort sort) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<S> query = builder.createQuery(domainClass);
@@ -622,7 +625,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
query.select(root);
if (sort != null && !sort.isUnsorted()) {
if (sort.isSorted()) {
query.orderBy(toOrders(sort, root, builder));
}
@@ -637,7 +640,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* @deprecated override {@link #getCountQuery(Specification, Class)} instead
*/
@Deprecated
protected TypedQuery<Long> getCountQuery(Specification<T> spec) {
protected TypedQuery<Long> getCountQuery(@Nullable Specification<T> spec) {
return getCountQuery(spec, getDomainClass());
}
@@ -648,7 +651,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* @param domainClass must not be {@literal null}.
* @return
*/
protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {
protected <S extends T> TypedQuery<Long> getCountQuery(@Nullable Specification<S> spec, Class<S> domainClass) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> query = builder.createQuery(Long.class);
@@ -675,7 +678,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
* @param query must not be {@literal null}.
* @return
*/
private <S, U extends T> Root<U> applySpecificationToCriteria(Specification<U> spec, Class<U> domainClass,
private <S, U extends T> Root<U> applySpecificationToCriteria(@Nullable Specification<U> spec, Class<U> domainClass,
CriteriaQuery<S> query) {
Assert.notNull(domainClass, "Domain class must not be null!");
@@ -739,7 +742,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
}
private static boolean isUnpaged(Pageable pageable) {
return pageable == null || pageable.isUnpaged();
return pageable.isUnpaged();
}
/**
@@ -755,9 +758,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
private final JpaEntityInformation<T, ?> entityInformation;
ParameterExpression<Iterable> parameter;
@Nullable ParameterExpression<Iterable> parameter;
public ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {
ByIdsSpecification(JpaEntityInformation<T, ?> entityInformation) {
this.entityInformation = entityInformation;
}
@@ -790,7 +793,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepository<T, ID>, JpaSpec
*
* @param example
*/
public ExampleSpecification(Example<T> example) {
ExampleSpecification(Example<T> example) {
Assert.notNull(example, "Example must not be null!");
this.example = example;

View File

@@ -1,5 +1,7 @@
/**
* JPA repository implementations.
*/
@NonNullApi
package org.springframework.data.jpa.repository.support;
import org.springframework.lang.NonNullApi;

View File

@@ -39,6 +39,7 @@ import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.lang.Nullable;
import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo;
import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor;
import org.springframework.util.Assert;
@@ -51,6 +52,7 @@ import org.springframework.util.StringUtils;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
public class ClasspathScanningPersistenceUnitPostProcessor
implements PersistenceUnitPostProcessor, ResourceLoaderAware, EnvironmentAware {
@@ -62,7 +64,7 @@ public class ClasspathScanningPersistenceUnitPostProcessor
private ResourcePatternResolver mappingFileResolver = new PathMatchingResourcePatternResolver();
private Environment environment = new StandardEnvironment();
private ResourceLoader resourceLoader = new DefaultResourceLoader();
private String mappingFileNamePattern;
private @Nullable String mappingFileNamePattern;
/**
* Creates a new {@link ClasspathScanningPersistenceUnitPostProcessor} using the given base package as scan base.
@@ -125,7 +127,10 @@ public class ClasspathScanningPersistenceUnitPostProcessor
for (BeanDefinition definition : provider.findCandidateComponents(basePackage)) {
LOG.debug("Registering classpath-scanned entity {} in persistence unit info!", definition.getBeanClassName());
pui.addManagedClassName(definition.getBeanClassName());
if (definition.getBeanClassName() != null) {
pui.addManagedClassName(definition.getBeanClassName());
}
}
for (String location : scanForMappingFileLocations()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2011-2013 the original author or authors.
* Copyright 2011-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -46,7 +46,7 @@ public class MergingPersistenceUnitManager extends DefaultPersistenceUnitManager
// Invoke normal post processing
super.postProcessPersistenceUnitInfo(pui);
PersistenceUnitInfo oldPui = getPersistenceUnitInfo(pui.getPersistenceUnitName());
PersistenceUnitInfo oldPui = getPersistenceUnitInfo(((PersistenceUnitInfo) pui).getPersistenceUnitName());
if (oldPui != null) {
postProcessPersistenceUnitInfo(pui, oldPui);

View File

@@ -1,5 +1,7 @@
/**
* Various helper classes useful when working with JPA.
*/
@NonNullApi
package org.springframework.data.jpa.support;
import org.springframework.lang.NonNullApi;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2014-2016 the original author or authors.
* Copyright 2014-2017 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.
@@ -41,6 +41,7 @@ import org.springframework.util.ClassUtils;
* Utility methods to work with {@link BeanDefinition} instances from {@link BeanFactoryPostProcessor}s.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public class BeanDefinitionUtils {
@@ -127,8 +128,10 @@ public class BeanDefinitionUtils {
if (!EntityManagerFactory.class.getName().equals(definition.getPropertyValues().get("expectedType"))) {
return;
}
} else if (beanFactory.getType(name) == null
|| !EntityManagerFactory.class.isAssignableFrom(beanFactory.getType(name))) {
}
Class<?> type = beanFactory.getType(name);
if (type == null || !EntityManagerFactory.class.isAssignableFrom(type)) {
return;
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.jpa.util;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.persistence.metamodel.ManagedType;
@@ -29,12 +30,13 @@ import org.springframework.util.Assert;
* Wrapper around the JPA {@link Metamodel} to be able to apply some fixes against bugs in provider implementations.
*
* @author Oliver Gierke
* @author Mark Paluch
*/
public class JpaMetamodel {
private final Metamodel metamodel;
private Collection<Class<?>> managedTypes;
private Optional<Collection<Class<?>>> managedTypes = Optional.empty();
/**
* Creates a new {@link JpaMetamodel} for the given JPA {@link Metamodel}.
@@ -70,24 +72,23 @@ public class JpaMetamodel {
*/
private Collection<Class<?>> getManagedTypes() {
if (managedTypes != null) {
return managedTypes;
}
if (!managedTypes.isPresent()) {
Set<ManagedType<?>> managedTypes = metamodel.getManagedTypes();
Set<Class<?>> types = new HashSet<Class<?>>(managedTypes.size());
Set<ManagedType<?>> managedTypes = metamodel.getManagedTypes();
Set<Class<?>> types = new HashSet<Class<?>>(managedTypes.size());
for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
for (ManagedType<?> managedType : metamodel.getManagedTypes()) {
Class<?> type = managedType.getJavaType();
Class<?> type = managedType.getJavaType();
if (type != null) {
types.add(type);
if (type != null) {
types.add(type);
}
}
this.managedTypes = Optional.of(Collections.unmodifiableSet(types));
}
this.managedTypes = Collections.unmodifiableSet(types);
return this.managedTypes;
return this.managedTypes.get();
}
}

View File

@@ -0,0 +1,7 @@
/**
* Spring Data JPA utilities.
*/
@NonNullApi
package org.springframework.data.jpa.util;
import org.springframework.lang.NonNullApi;

View File

@@ -35,6 +35,7 @@ import org.springframework.data.jpa.domain.sample.Address_;
import org.springframework.data.jpa.domain.sample.MailMessage_;
import org.springframework.data.jpa.domain.sample.MailSender_;
import org.springframework.data.jpa.domain.sample.User_;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -52,10 +53,10 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration("classpath:infrastructure.xml")
public class JpaSortTests {
private static final Attribute<?, ?> NULL_ATTRIBUTE = null;
private static final @Nullable Attribute<?, ?> NULL_ATTRIBUTE = null;
private static final Attribute<?, ?>[] EMPTY_ATTRIBUTES = new Attribute<?, ?>[0];
private static final PluralAttribute<?, ?, ?> NULL_PLURAL_ATTRIBUTE = null;
private static final @Nullable PluralAttribute<?, ?, ?> NULL_PLURAL_ATTRIBUTE = null;
private static final PluralAttribute<?, ?, ?>[] EMPTY_PLURAL_ATTRIBUTES = new PluralAttribute<?, ?, ?>[0];
@Test(expected = IllegalArgumentException.class) // DATAJPA-12

View File

@@ -15,7 +15,6 @@
*/
package org.springframework.data.jpa.domain.sample;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
@@ -25,11 +24,12 @@ import javax.persistence.ManyToMany;
import javax.persistence.NamedQuery;
import org.springframework.data.jpa.domain.AbstractAuditable;
import org.springframework.lang.Nullable;
/**
* Sample auditable user to demonstrate working with {@code AbstractAuditableEntity}. No declaration of an ID is
* necessary. Furthermore no auditing information has to be declared explicitly.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -41,24 +41,25 @@ public class AuditableUser extends AbstractAuditable<AuditableUser, Integer> {
private String firstname;
@ManyToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }) private Set<AuditableRole> roles = new HashSet<AuditableRole>();
@ManyToMany(
cascade = { CascadeType.PERSIST, CascadeType.MERGE }) private final Set<AuditableRole> roles = new HashSet<>();
public AuditableUser() {
this(null);
}
public AuditableUser(Integer id) {
public AuditableUser(@Nullable Integer id) {
this(id, null);
}
public AuditableUser(Integer id, String firstname) {
public AuditableUser(@Nullable Integer id, String firstname) {
setId(id);
this.firstname = firstname;
}
/**
* Returns the firstname.
*
*
* @return the firstname
*/
public String getFirstname() {
@@ -68,7 +69,7 @@ public class AuditableUser extends AbstractAuditable<AuditableUser, Integer> {
/**
* Sets the firstname.
*
*
* @param firstname the firstname to set
*/
public void setFirstname(final String firstname) {

View File

@@ -18,7 +18,6 @@ package org.springframework.data.jpa.domain.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Optional;
@@ -40,7 +39,7 @@ import org.springframework.transaction.annotation.Transactional;
/**
* Integration test for {@link AuditingEntityListener}.
*
*
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2008-2014 the original author or authors.
* Copyright 2008-2017 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.
@@ -43,14 +43,6 @@ public class EclipseLinkNamespaceUserRepositoryTests extends NamespaceUserReposi
}
/**
* Ignored until https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 is resolved.
*/
@Override
public void allowsExecutingPageableMethodWithNullPageable() {
}
/**
* Ignored until https://bugs.eclipse.org/bugs/show_bug.cgi?id=349477 is resolved.
*/

View File

@@ -161,11 +161,6 @@ public class UserRepositoryTests {
secondUser, thirdUser);
}
@Test
public void savingNullCollectionIsNoOp() throws Exception {
assertThat(repository.saveAll(null)).isEmpty();
}
@Test
public void savingEmptyCollectionIsNoOp() throws Exception {
assertThat(repository.saveAll(new ArrayList<>())).isEmpty();
@@ -536,7 +531,7 @@ public class UserRepositoryTests {
public void returnsSameListIfNoSortIsGiven() throws Exception {
flushTestUsers();
assertSameElements(repository.findAll((Sort) null), repository.findAll());
assertSameElements(repository.findAll(Sort.unsorted()), repository.findAll());
}
@Test
@@ -552,7 +547,7 @@ public class UserRepositoryTests {
public void returnsAllAsPageIfNoPageableIsGiven() throws Exception {
flushTestUsers();
assertThat(repository.findAll((Pageable) null)).isEqualTo(new PageImpl<User>(repository.findAll()));
assertThat(repository.findAll(Pageable.unpaged())).isEqualTo(new PageImpl<>(repository.findAll()));
}
@Test
@@ -569,7 +564,7 @@ public class UserRepositoryTests {
@Test
public void executesPagedSpecificationsCorrectly() throws Exception {
Page<User> result = executeSpecWithSort(null);
Page<User> result = executeSpecWithSort(Sort.unsorted());
assertThat(result.getContent()).isSubsetOf(firstUser, thirdUser);
}
@@ -758,17 +753,17 @@ public class UserRepositoryTests {
}
@Test // DATAJPA-201
public void allowsExecutingPageableMethodWithNullPageable() {
public void allowsExecutingPageableMethodWithUnpagedArgument() {
flushTestUsers();
assertThat(repository.findByFirstname("Oliver", null)).containsOnly(firstUser);
Page<User> page = repository.findByFirstnameIn(null, "Oliver");
Page<User> page = repository.findByFirstnameIn(Pageable.unpaged(), "Oliver");
assertThat(page.getNumberOfElements()).isEqualTo(1);
assertThat(page.getContent()).contains(firstUser);
page = repository.findAll((Pageable) null);
page = repository.findAll(Pageable.unpaged());
assertThat(page.getNumberOfElements()).isEqualTo(4);
assertThat(page.getContent()).contains(firstUser, secondUser, thirdUser, fourthUser);
}
@@ -868,6 +863,7 @@ public class UserRepositoryTests {
flushTestUsers();
Page<User> page = repository.findAll(new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.get("lastname"), "Gierke");
}
@@ -941,11 +937,10 @@ public class UserRepositoryTests {
assertThat(repository.existsByLastname("Hans Peter")).isEqualTo(false);
}
@Test // DATAJPA-332
@Test // DATAJPA-332, DATAJPA-1168
public void findAllReturnsEmptyIterableIfNoIdsGiven() {
assertThat(repository.findAllById(Collections.<Integer> emptySet())).isEmpty();
assertThat(repository.findAllById((Iterable<Integer>) null)).isEmpty();
}
@Test // DATAJPA-391
@@ -1171,7 +1166,7 @@ public class UserRepositoryTests {
flushTestUsers();
List<User> result = repository.findByAttributesIn(new HashSet<String>(Arrays.asList("cool", "hip")));
List<User> result = repository.findByAttributesIn(new HashSet<>(Arrays.asList("cool", "hip")));
assertThat(result).containsOnly(firstUser, secondUser);
}
@@ -1230,7 +1225,7 @@ public class UserRepositoryTests {
flushTestUsers();
byte[] result = null; // repository.findBinaryDataByIdJpaQl(firstUser.getId());
byte[] result = repository.findBinaryDataByIdNative(firstUser.getId());
assertThat(result.length).isEqualTo(data.length);
assertThat(result).isEqualTo(data);
@@ -1640,7 +1635,7 @@ public class UserRepositoryTests {
Stream<User> stream = repository.findAllByCustomQueryAndStream();
final List<User> users = new ArrayList<User>();
final List<User> users = new ArrayList<>();
try {
@@ -1666,7 +1661,7 @@ public class UserRepositoryTests {
Stream<User> stream = repository.readAllByFirstnameNotNull();
final List<User> users = new ArrayList<User>();
final List<User> users = new ArrayList<>();
try {
@@ -1692,7 +1687,7 @@ public class UserRepositoryTests {
Stream<User> stream = repository.streamAllPaged(PageRequest.of(0, 2));
final List<User> users = new ArrayList<User>();
final List<User> users = new ArrayList<>();
try {

View File

@@ -26,7 +26,6 @@ import org.springframework.data.jpa.repository.custom.UserCustomExtendedReposito
import org.springframework.data.jpa.repository.support.TransactionalRepositoryTests.DelegatingTransactionManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
/**
* Annotation to exclude repository interfaces from being picked up and thus in consequence getting an instance being
@@ -36,7 +35,7 @@ import org.springframework.util.Assert;
* custom repository base class to implement methods declared in that intermediate interface. In this case you typically
* derive your concrete repository interfaces from the intermediate one but don't want to create a Spring bean for the
* intermediate interface.
*
*
* @author Oliver Gierke
* @author Mark Paluch
*/
@@ -44,11 +43,9 @@ import org.springframework.util.Assert;
@ContextConfiguration(locations = "classpath:config/namespace-customfactory-context.xml")
public class CustomRepositoryFactoryConfigTests {
@Autowired(required = false)
UserCustomExtendedRepository userRepository;
@Autowired(required = false) UserCustomExtendedRepository userRepository;
@Autowired
DelegatingTransactionManager transactionManager;
@Autowired DelegatingTransactionManager transactionManager;
@Before
public void setup() {

View File

@@ -0,0 +1,4 @@
@NonNullApi
package org.springframework.data.jpa.repository.custom;
import org.springframework.lang.NonNullApi;

View File

@@ -35,6 +35,7 @@ import org.springframework.transaction.annotation.Transactional;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:application-context.xml")
@@ -91,7 +92,7 @@ public class Jpa21UtilsTests {
assertThat(colleagues, terminatesGraphWith("roles"));
assertThat(colleagues, hasSubgraphs("colleagues"));
AttributeNode colleaguesOfColleagues = findNode("colleagues", colleagues);
AttributeNode<?> colleaguesOfColleagues = findNode("colleagues", colleagues);
assertThat(colleaguesOfColleagues, terminatesGraphWith("roles"));
}
@@ -111,7 +112,7 @@ public class Jpa21UtilsTests {
assertThat(colleagues, terminatesGraphWith("roles"));
assertThat(colleagues, hasSubgraphs("colleagues"));
AttributeNode colleaguesOfColleagues = findNode("colleagues", colleagues);
AttributeNode<?> colleaguesOfColleagues = findNode("colleagues", colleagues);
assertThat(colleaguesOfColleagues, terminatesGraphWith("roles"));
}
@@ -131,7 +132,7 @@ public class Jpa21UtilsTests {
assertThat(colleagues, terminatesGraphWith("roles"));
assertThat(colleagues, hasSubgraphs("colleagues"));
AttributeNode colleaguesOfColleagues = findNode("colleagues", colleagues);
AttributeNode<?> colleaguesOfColleagues = findNode("colleagues", colleagues);
assertThat(colleaguesOfColleagues, terminatesGraphWith("roles"));
}

View File

@@ -26,12 +26,11 @@ import org.junit.rules.ExpectedException;
import org.springframework.data.jpa.repository.query.StringQuery.InParameterBinding;
import org.springframework.data.jpa.repository.query.StringQuery.LikeParameterBinding;
import org.springframework.data.jpa.repository.query.StringQuery.ParameterBinding;
import org.springframework.data.repository.query.Param;
import org.springframework.data.repository.query.parser.Part.Type;
/**
* Unit tests for {@link StringQuery}.
*
*
* @author Oliver Gierke
* @author Thomas Darimont
*/
@@ -281,7 +280,8 @@ public class StringQueryUnitTests {
}
/**
* @see <a href="download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf">JPA 2.1 specification, section 4.8</a>
* @see <a href="download.oracle.com/otn-pub/jcp/persistence-2_1-fr-eval-spec/JavaPersistence.pdf">JPA 2.1
* specification, section 4.8</a>
*/
@Test // DATAJPA-886
public void detectsConstructorExpressionForDefaultConstructor() {

View File

@@ -22,7 +22,6 @@ import static org.mockito.Mockito.*;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.metamodel.Metamodel;

View File

@@ -25,18 +25,20 @@ import javax.persistence.Subgraph;
import org.hamcrest.Description;
import org.hamcrest.TypeSafeMatcher;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
/**
* @author Christoph Strobl
* @author Mark Paluch
*/
public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
private boolean terminatingNodeCheck = false;
private List<String> nodes;
private List<String> subgraphs;
private List<String> errors = new ArrayList<String>();
private final List<String> errors = new ArrayList<>();
@Override
protected boolean matchesSafely(AttributeNode<T> item) {
@@ -129,7 +131,7 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
* @param graph
* @return
*/
public static AttributeNode<?> findNode(String nodeName, EntityGraph<?> graph) {
public static AttributeNode<?> findNode(String nodeName, @Nullable EntityGraph<?> graph) {
if (graph == null) {
return null;
@@ -145,6 +147,7 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
* @param nodes
* @return
*/
@Nullable
public static AttributeNode<?> findNode(String nodeName, List<AttributeNode<?>> nodes) {
if (CollectionUtils.isEmpty(nodes)) {
@@ -168,6 +171,7 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
* @param node
* @return
*/
@Nullable
public static AttributeNode<?> findNode(String attributeName, AttributeNode<?> node) {
if (CollectionUtils.isEmpty(node.getSubgraphs())) {
@@ -180,7 +184,7 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
private List<String> extractExistingAttributeNames(Subgraph<?> graph) {
List<String> result = new ArrayList<String>(graph.getAttributeNodes().size());
List<String> result = new ArrayList<>(graph.getAttributeNodes().size());
for (AttributeNode<?> node : graph.getAttributeNodes()) {
result.add(node.getAttributeName());
}
@@ -193,9 +197,9 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
* @param nodeNames
* @return
*/
public static IsAttributeNode terminatesGraphWith(String... nodeNames) {
public static <T> IsAttributeNode<T> terminatesGraphWith(String... nodeNames) {
IsAttributeNode matcher = new IsAttributeNode();
IsAttributeNode<T> matcher = new IsAttributeNode<>();
matcher.nodes = Arrays.asList(nodeNames);
return matcher;
}
@@ -206,9 +210,9 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
*
* @return
*/
public static IsAttributeNode hasSubgraphs(String... subgraphNames) {
public static <T> IsAttributeNode<T> hasSubgraphs(String... subgraphNames) {
IsAttributeNode matcher = new IsAttributeNode();
IsAttributeNode<T> matcher = new IsAttributeNode<>();
matcher.subgraphs = Arrays.asList(subgraphNames);
return matcher;
}
@@ -219,9 +223,9 @@ public class IsAttributeNode<T> extends TypeSafeMatcher<AttributeNode<T>> {
*
* @return
*/
public static IsAttributeNode terminatesGraph() {
public static <T> IsAttributeNode<T> terminatesGraph() {
IsAttributeNode matcher = new IsAttributeNode();
IsAttributeNode<T> matcher = new IsAttributeNode<>();
matcher.terminatingNodeCheck = true;
return matcher;
}