DATACMNS-1114 - Introduced usage of nullable annotations for API validation.

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

Removed null handling from converters for JodaTime and ThreeTenBP. Introduced factory methods Page.empty() and Page.empty(Pageable). Introduced default methods getRequiredGetter(), …Setter() and …Field() on PersistentProperty to allow non-nullable lookups of members. The same for TypeInformation.getrequiredActualType(), …SuperTypeInformation().

Tweaked PersistentPropertyCreator.addPropertiesForRemainingDescriptors() to filter unsuitable PropertyDescriptors before actually trying to create a Property instance from them as the new stronger nullability requirements would cause exceptions downstream.

Lazy.get() now expects a non-null return value. Clients being able to cope with null need to call ….orElse(…).

Original pull request: #232.
This commit is contained in:
Oliver Gierke
2017-06-27 08:41:16 +02:00
parent d9b16d8a27
commit 049970874d
234 changed files with 2274 additions and 1179 deletions

View File

@@ -56,6 +56,7 @@ public class QSort extends Sort implements Serializable {
*
* @param orderSpecifiers must not be {@literal null}.
*/
@SuppressWarnings("deprecation")
public QSort(List<OrderSpecifier<?>> orderSpecifiers) {
super(toOrders(orderSpecifiers));

View File

@@ -17,6 +17,7 @@ package org.springframework.data.querydsl;
import lombok.experimental.UtilityClass;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
import com.querydsl.core.types.Path;
@@ -52,7 +53,7 @@ public class QuerydslUtils {
* @param tail must not be {@literal null}.
* @return
*/
private static String toDotPath(Path<?> path, String tail) {
private static String toDotPath(@Nullable Path<?> path, String tail) {
if (path == null) {
return tail;

View File

@@ -19,6 +19,7 @@ import java.beans.PropertyDescriptor;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.lang.Nullable;
import com.querydsl.core.types.Path;
@@ -56,6 +57,7 @@ interface PathInformation {
*
* @return
*/
@Nullable
PropertyDescriptor getLeafPropertyDescriptor();
/**

View File

@@ -28,6 +28,7 @@ import org.springframework.beans.BeanUtils;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.ReflectionUtils;
import com.querydsl.core.types.Path;
@@ -69,45 +70,46 @@ class PropertyPathInformation implements PathInformation {
return PropertyPathInformation.of(PropertyPath.from(path, type));
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#getLeafType()
* @see org.springframework.data.querydsl.binding.PathInformation#getLeafType()
*/
@Override
public Class<?> getLeafType() {
return path.getLeafProperty().getType();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#getLeafParentType()
* @see org.springframework.data.querydsl.binding.PathInformation#getLeafParentType()
*/
@Override
public Class<?> getLeafParentType() {
return path.getLeafProperty().getOwningType().getType();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#getLeafProperty()
* @see org.springframework.data.querydsl.binding.PathInformation#getLeafProperty()
*/
@Override
public String getLeafProperty() {
return path.getLeafProperty().getSegment();
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#getLeafPropertyDescriptor()
* @see org.springframework.data.querydsl.binding.PathInformation#getLeafPropertyDescriptor()
*/
@Nullable
@Override
public PropertyDescriptor getLeafPropertyDescriptor() {
return BeanUtils.getPropertyDescriptor(getLeafParentType(), getLeafProperty());
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#toDotPath()
* @see org.springframework.data.querydsl.binding.PathInformation#toDotPath()
*/
@Override
public String toDotPath() {
@@ -125,8 +127,7 @@ class PropertyPathInformation implements PathInformation {
private static Path<?> reifyPath(EntityPathResolver resolver, PropertyPath path, Optional<Path<?>> base) {
Optional<Path<?>> map = base.filter(it -> it instanceof CollectionPathBase)
.map(CollectionPathBase.class::cast)//
Optional<Path<?>> map = base.filter(it -> it instanceof CollectionPathBase).map(CollectionPathBase.class::cast)//
.map(CollectionPathBase::any)//
.map(Path.class::cast)//
.map(it -> reifyPath(resolver, path, Optional.of(it)));
@@ -135,11 +136,14 @@ class PropertyPathInformation implements PathInformation {
Path<?> entityPath = base.orElseGet(() -> resolver.createPath(path.getOwningType().getType()));
Field field = ReflectionUtils.findField(entityPath.getClass(), path.getSegment());
Field field = org.springframework.data.util.ReflectionUtils.findRequiredField(entityPath.getClass(),
path.getSegment());
Object value = ReflectionUtils.getField(field, entityPath);
if (path.hasNext()) {
return reifyPath(resolver, path.next(), Optional.of((Path<?>) value));
PropertyPath next = path.next();
if (next != null) {
return reifyPath(resolver, next, Optional.of((Path<?>) value));
}
return (Path<?>) value;

View File

@@ -32,6 +32,7 @@ import org.springframework.data.mapping.PropertyReferenceException;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -239,6 +240,7 @@ public class QuerydslBindings {
* @param type must not be {@literal null}.
* @return
*/
@Nullable
PathInformation getPropertyPath(String path, TypeInformation<?> type) {
Assert.notNull(path, "Path must not be null!");
@@ -316,8 +318,18 @@ public class QuerydslBindings {
* @return
*/
private static String toDotPath(Optional<Path<?>> path) {
return path.map(it -> it.toString().substring(it.getMetadata().getRootPath().getMetadata().getName().length() + 1))
.orElse("");
return path.map(QuerydslBindings::fromRootPath).orElse("");
}
private static String fromRootPath(Path<?> path) {
Path<?> rootPath = path.getMetadata().getRootPath();
if (rootPath == null) {
throw new IllegalStateException(String.format("Couldn't find root path on path %s!", path));
}
return path.toString().substring(rootPath.getMetadata().getName().length() + 1);
}
/**
@@ -386,7 +398,7 @@ public class QuerydslBindings {
*/
public class AliasingPathBinder<P extends Path<? extends T>, T> extends PathBinder<P, T> {
private final String alias;
private final @Nullable String alias;
private final P path;
/**
@@ -404,7 +416,7 @@ public class QuerydslBindings {
* @param alias can be {@literal null}.
* @param path must not be {@literal null}.
*/
private AliasingPathBinder(String alias, P path) {
private AliasingPathBinder(@Nullable String alias, P path) {
super(path);

View File

@@ -24,6 +24,7 @@ import java.beans.PropertyDescriptor;
import org.springframework.beans.BeanUtils;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.QuerydslUtils;
import org.springframework.lang.Nullable;
import com.querydsl.core.types.Path;
@@ -55,7 +56,14 @@ class QuerydslPathInformation implements PathInformation {
*/
@Override
public Class<?> getLeafParentType() {
return path.getMetadata().getParent().getType();
Path<?> parent = path.getMetadata().getParent();
if (parent == null) {
throw new IllegalStateException(String.format("Could not obtain metadata for parent node of %s!", path));
}
return parent.getType();
}
/*
@@ -71,6 +79,7 @@ class QuerydslPathInformation implements PathInformation {
* (non-Javadoc)
* @see org.springframework.data.querydsl.binding.MappedPath#getLeafPropertyDescriptor()
*/
@Nullable
@Override
public PropertyDescriptor getLeafPropertyDescriptor() {
return BeanUtils.getPropertyDescriptor(getLeafParentType(), getLeafProperty());

View File

@@ -32,9 +32,9 @@ import org.springframework.core.convert.TypeDescriptor;
import org.springframework.data.mapping.PropertyPath;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import com.querydsl.core.BooleanBuilder;
@@ -81,6 +81,7 @@ public class QuerydslPredicateBuilder {
* @param bindings the {@link QuerydslBindings} for the predicate.
* @return
*/
@Nullable
public Predicate getPredicate(TypeInformation<?> type, MultiValueMap<String, String> values,
QuerydslBindings bindings) {
@@ -173,7 +174,8 @@ public class QuerydslPredicateBuilder {
for (String value : source) {
target.add(conversionService.canConvert(String.class, targetType)
? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path)) : value);
? conversionService.convert(value, TypeDescriptor.forObject(value), getTargetTypeDescriptor(path))
: value);
}
return target;
@@ -193,12 +195,17 @@ public class QuerydslPredicateBuilder {
Class<?> owningType = path.getLeafParentType();
String leafProperty = path.getLeafProperty();
if (descriptor == null) {
return TypeDescriptor.nested(ReflectionUtils.findField(owningType, leafProperty), 0);
TypeDescriptor result = descriptor == null //
? TypeDescriptor
.nested(org.springframework.data.util.ReflectionUtils.findRequiredField(owningType, leafProperty), 0)
: TypeDescriptor
.nested(new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty), 0);
if (result == null) {
throw new IllegalStateException(String.format("Could not obtain TypeDesciptor for PathInformation %s!", path));
}
return TypeDescriptor
.nested(new Property(owningType, descriptor.getReadMethod(), descriptor.getWriteMethod(), leafProperty), 0);
return result;
}
/**

View File

@@ -0,0 +1,5 @@
/**
* Base classes to implement CDI support for repositories.
*/
@org.springframework.lang.NonNullApi
package org.springframework.data.querydsl.binding;

View File

@@ -3,4 +3,5 @@
*
* @see <a href="http://www.querydsl.com">http://www.querydsl.com</a>
*/
package org.springframework.data.querydsl;
@org.springframework.lang.NonNullApi
package org.springframework.data.querydsl;