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:
committed by
Christoph Strobl
parent
0273476ba6
commit
2e3e5f67bc
@@ -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;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Spring Data JPA specific converter infrastructure.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.convert;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Spring Data JPA specific JSR-310 converters.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.convert.threeten;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Spring Data JPA specific ThreeTenBp converters.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.convert.threetenbp;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) -> {
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* JPA specific support classes to implement domain classes.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.domain;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Implementation classes for auditing with JPA.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.domain.support;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* JPA provider-specific utilities.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.provider;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* CDI support for Spring Data JPA Repositories.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository.cdi;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Classes for JPA namespace configuration.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository.config;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Interfaces and annotations for JPA specific repositories.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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!");
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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!");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Query implementation to exectue queries against JPA.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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();
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* JPA repository implementations.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository.support;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
/**
|
||||
* Various helper classes useful when working with JPA.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.support;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Spring Data JPA utilities.
|
||||
*/
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.util;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
@NonNullApi
|
||||
package org.springframework.data.jpa.repository.custom;
|
||||
|
||||
import org.springframework.lang.NonNullApi;
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user