DATACMNS-867 - Rework utility classes.

Removed the additional methods that reflectively checked for the Stream type and whether a Method instance is a default method. Turned utility classes into interfaces where possible. Make use of Lombok's @UtilityClass where not.

Removed obsolete implementation class in StreamUtils in favor of a lambda.
This commit is contained in:
Oliver Gierke
2017-03-14 09:39:30 +01:00
parent 6e3114f3cb
commit 1c60ea8d36
9 changed files with 60 additions and 116 deletions

View File

@@ -57,7 +57,7 @@ public class DefaultMethodInvokingMethodInterceptor implements MethodInterceptor
Method method = invocation.getMethod();
if (!org.springframework.data.util.ReflectionUtils.isDefaultMethod(method)) {
if (!method.isDefault()) {
return invocation.proceed();
}

View File

@@ -19,6 +19,7 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
@@ -28,7 +29,6 @@ import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.repository.util.ReactiveWrappers;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -140,7 +140,7 @@ public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
Class<?> rawType = type.getType();
boolean needToUnwrap = Iterable.class.isAssignableFrom(rawType) || rawType.isArray()
|| QueryExecutionConverters.supports(rawType) || ReflectionUtils.isJava8StreamType(rawType);
|| QueryExecutionConverters.supports(rawType) || Stream.class.isAssignableFrom(rawType);
return needToUnwrap ? unwrapWrapperTypes(type.getRequiredComponentType()) : rawType;
}

View File

@@ -43,7 +43,6 @@ import org.springframework.data.repository.core.CrudMethods;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.util.Optionals;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.Streamable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -185,7 +184,7 @@ class DefaultRepositoryInformation implements RepositoryInformation {
* @return
*/
private boolean isQueryMethodCandidate(Method method) {
return !method.isBridge() && !ReflectionUtils.isDefaultMethod(method) //
return !method.isBridge() && !method.isDefault() //
&& !Modifier.isStatic(method.getModifiers()) //
&& (isQueryAnnotationPresentOn(method) || !isCustomMethod(method) && !isBaseClassMethod(method));
}

View File

@@ -364,9 +364,10 @@ public abstract class RepositoryFactorySupport implements BeanClassLoaderAware,
Class<?> baseClass = information.getRepositoryBaseClass();
Optional<Constructor<?>> constructor = ReflectionUtils.findConstructor(baseClass, constructorArguments);
return constructor.map(it -> (R) BeanUtils.instantiateClass(it, constructorArguments)).orElseThrow(() -> new IllegalStateException(String.format(
"No suitable constructor found on %s to match the given arguments: %s. Make sure you implement a constructor taking these",
baseClass, Arrays.stream(constructorArguments).map(Object::getClass).collect(Collectors.toList()))));
return constructor.map(it -> (R) BeanUtils.instantiateClass(it, constructorArguments))
.orElseThrow(() -> new IllegalStateException(String.format(
"No suitable constructor found on %s to match the given arguments: %s. Make sure you implement a constructor taking these",
baseClass, Arrays.stream(constructorArguments).map(Object::getClass).collect(Collectors.toList()))));
}
/**

View File

@@ -19,6 +19,7 @@ import static org.springframework.data.repository.util.ClassUtils.*;
import java.lang.reflect.Method;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -30,7 +31,6 @@ import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.util.QueryExecutionConverters;
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.Lazy;
import org.springframework.data.util.ReflectionUtils;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.Assert;
@@ -232,7 +232,7 @@ public class QueryMethod {
* @since 1.10
*/
public boolean isStreamQuery() {
return ReflectionUtils.isJava8StreamType(unwrappedReturnType);
return Stream.class.isAssignableFrom(unwrappedReturnType);
}
/**

View File

@@ -1,12 +1,24 @@
/*
* 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.util;
import lombok.experimental.UtilityClass;
@UtilityClass
public class CastUtils {
public interface CastUtils {
@SuppressWarnings("unchecked")
public <T> T cast(Object object) {
public static <T> T cast(Object object) {
return (T) object;
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.data.util;
import lombok.experimental.UtilityClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -29,7 +31,8 @@ import org.springframework.util.StringUtils;
* @author Oliver Gierke
* @since 1.5
*/
public abstract class ParsingUtils {
@UtilityClass
public class ParsingUtils {
private static final String UPPER = "\\p{Lu}|\\P{InBASIC_LATIN}";
private static final String LOWER = "\\p{Ll}";
@@ -38,8 +41,6 @@ public abstract class ParsingUtils {
private static final Pattern CAMEL_CASE = Pattern.compile(CAMEL_CASE_REGEX);
private ParsingUtils() {}
/**
* Splits up the given camel-case {@link String}.
*

View File

@@ -17,12 +17,12 @@ package org.springframework.data.util;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.experimental.UtilityClass;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
@@ -45,22 +45,8 @@ import org.springframework.util.ReflectionUtils.FieldFilter;
* @author Christoph Strobl
* @since 1.5
*/
public abstract class ReflectionUtils {
private static final Class<?> JAVA8_STREAM_TYPE;
static {
Class<?> cls = null;
try {
cls = Class.forName("java.util.stream.Stream");
} catch (ClassNotFoundException ignore) {}
JAVA8_STREAM_TYPE = cls;
}
private ReflectionUtils() {}
@UtilityClass
public class ReflectionUtils {
/**
* Creates an instance of the class with the given fully qualified name or returns the given default instance if the
@@ -81,18 +67,6 @@ public abstract class ReflectionUtils {
}
}
/**
* Back-port of Java 8's {@code isDefault()} method on {@link Method}.
*
* @param method must not be {@literal null}.
* @return
*/
public static boolean isDefaultMethod(Method method) {
return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC)
&& method.getDeclaringClass().isInterface();
}
/**
* A {@link FieldFilter} that has a description.
*
@@ -227,21 +201,6 @@ public abstract class ReflectionUtils {
org.springframework.util.ReflectionUtils.setField(field, target, value);
}
/**
* Tests whether the given type is assignable to a Java 8 {@link Stream}.
*
* @param type can be {@literal null}.
* @return
*/
public static boolean isJava8StreamType(Class<?> type) {
if (type == null || JAVA8_STREAM_TYPE == null) {
return false;
}
return JAVA8_STREAM_TYPE.isAssignableFrom(type);
}
/**
* Finds a constructor on the given type that matches the given constructor arguments.
*
@@ -276,15 +235,31 @@ public abstract class ReflectionUtils {
return Stream.concat(returnType, parameterTypes);
}
/**
* Returns the {@link Method} with the given name and parameters declared on the given type, if available.
*
* @param type must not be {@literal null}.
* @param name must not be {@literal null} or empty.
* @param parameterTypes must not be {@literal null}.
* @return
* @since 2.0
*/
public static Optional<Method> getMethod(Class<?> type, String name, ResolvableType... parameterTypes) {
List<Class<?>> collect = Arrays.stream(parameterTypes).map(ResolvableType::getRawClass).collect(Collectors.toList());
Assert.notNull(type, "Type must not be null!");
Assert.hasText(name, "Name must not be null or empty!");
Assert.notNull(parameterTypes, "Parameter types must not be null!");
Optional<Method> method = Optional.ofNullable(
org.springframework.util.ReflectionUtils.findMethod(type, name, collect.toArray(new Class<?>[collect.size()])));
List<Class<?>> collect = Arrays.stream(parameterTypes)//
.map(ResolvableType::getRawClass)//
.collect(Collectors.toList());
return method.filter(it -> IntStream.range(0, it.getParameterCount())//
.allMatch(index -> ResolvableType.forMethodParameter(it, index).equals(parameterTypes[index])));
Method method = org.springframework.util.ReflectionUtils.findMethod(type, name,
collect.toArray(new Class<?>[collect.size()]));
return Optional.ofNullable(method)//
.filter(it -> IntStream.range(0, it.getParameterCount())//
.allMatch(index -> ResolvableType.forMethodParameter(it, index).equals(parameterTypes[index])));
}
private static boolean argumentsMatch(Class<?>[] parameterTypes, Object[] arguments) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015 the original author or authors.
* Copyright 2015-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.
@@ -30,9 +30,7 @@ import org.springframework.util.Assert;
* @author Oliver Gierke
* @since 1.10
*/
public class StreamUtils {
private StreamUtils() {}
public interface StreamUtils {
/**
* Returns a {@link Stream} backed by the given {@link Iterator}.
@@ -51,50 +49,8 @@ public class StreamUtils {
Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(iterator, Spliterator.NONNULL);
Stream<T> stream = StreamSupport.stream(spliterator, false);
return iterator instanceof CloseableIterator
? stream.onClose(new CloseableIteratorDisposingRunnable((CloseableIterator<T>) iterator)) : stream;
}
/**
* A {@link Runnable} that closes the given {@link CloseableIterator} in its {@link #run()} method. If the given
* {@code closeable} is {@literal null} the {@link #run()} method effectively becomes a noop.
* <p>
* Can be used in conjunction with streams as close action via:
*
* <pre>
* CloseableIterator<T> result = ...;
* Spliterator<T> spliterator = ...;
*
* return StreamSupport.stream(spliterator, false).onClose(new CloseableIteratorDisposingRunnable(result));
* </pre>
*
* @author Thomas Darimont
* @author Oliver Gierke
* @since 1.10
*/
private static class CloseableIteratorDisposingRunnable implements Runnable {
private CloseableIterator<?> closeable;
/**
* Creates a new {@link CloseableIteratorDisposingRunnable} for the given {@link CloseableIterator}.
*
* @param closeable can be {@literal null}.
*/
public CloseableIteratorDisposingRunnable(CloseableIterator<?> closeable) {
this.closeable = closeable;
}
/*
* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if (closeable != null) {
closeable.close();
}
}
return iterator instanceof CloseableIterator//
? stream.onClose(() -> ((CloseableIterator<T>) iterator).close()) //
: stream;
}
}