diff --git a/src/main/java/org/springframework/data/domain/Chunk.java b/src/main/java/org/springframework/data/domain/Chunk.java index 6b69285f0..8e6c0c037 100644 --- a/src/main/java/org/springframework/data/domain/Chunk.java +++ b/src/main/java/org/springframework/data/domain/Chunk.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; +import java.util.function.Function; import java.util.stream.Collectors; import org.springframework.core.convert.converter.Converter; @@ -156,11 +157,11 @@ abstract class Chunk implements Slice, Serializable { * @param converter must not be {@literal null}. * @return */ - protected List getConvertedContent(Converter converter) { + protected List getConvertedContent(Function converter) { Assert.notNull(converter, "Converter must not be null!"); - return this.stream().map(converter::convert).collect(Collectors.toList()); + return this.stream().map(converter::apply).collect(Collectors.toList()); } /* diff --git a/src/main/java/org/springframework/data/domain/Page.java b/src/main/java/org/springframework/data/domain/Page.java index 0254c1706..9e5b9aabf 100644 --- a/src/main/java/org/springframework/data/domain/Page.java +++ b/src/main/java/org/springframework/data/domain/Page.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2015 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. @@ -15,6 +15,8 @@ */ package org.springframework.data.domain; +import java.util.function.Function; + import org.springframework.core.convert.converter.Converter; /** @@ -47,5 +49,5 @@ public interface Page extends Slice { * @return a new {@link Page} with the content of the current one mapped by the given {@link Converter}. * @since 1.10 */ - Page map(Converter converter); + Page map(Function converter); } diff --git a/src/main/java/org/springframework/data/domain/PageImpl.java b/src/main/java/org/springframework/data/domain/PageImpl.java index 812adfd76..58b7f08df 100644 --- a/src/main/java/org/springframework/data/domain/PageImpl.java +++ b/src/main/java/org/springframework/data/domain/PageImpl.java @@ -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. @@ -17,8 +17,7 @@ package org.springframework.data.domain; import java.util.List; import java.util.Optional; - -import org.springframework.core.convert.converter.Converter; +import java.util.function.Function; /** * Basic {@code Page} implementation. @@ -106,7 +105,7 @@ public class PageImpl extends Chunk implements Page { * @see org.springframework.data.domain.Slice#transform(org.springframework.core.convert.converter.Converter) */ @Override - public Page map(Converter converter) { + public Page map(Function converter) { return new PageImpl<>(getConvertedContent(converter), pageable, total); } diff --git a/src/main/java/org/springframework/data/domain/Slice.java b/src/main/java/org/springframework/data/domain/Slice.java index 04268e600..8ad73582e 100644 --- a/src/main/java/org/springframework/data/domain/Slice.java +++ b/src/main/java/org/springframework/data/domain/Slice.java @@ -16,6 +16,7 @@ package org.springframework.data.domain; import java.util.List; +import java.util.function.Function; import org.springframework.core.convert.converter.Converter; import org.springframework.data.util.Streamable; @@ -124,5 +125,5 @@ public interface Slice extends Streamable { * @return a new {@link Slice} with the content of the current one mapped by the given {@link Converter}. * @since 1.10 */ - Slice map(Converter converter); + Slice map(Function converter); } diff --git a/src/main/java/org/springframework/data/domain/SliceImpl.java b/src/main/java/org/springframework/data/domain/SliceImpl.java index a2f0c3e3b..875842d1e 100644 --- a/src/main/java/org/springframework/data/domain/SliceImpl.java +++ b/src/main/java/org/springframework/data/domain/SliceImpl.java @@ -16,8 +16,7 @@ package org.springframework.data.domain; import java.util.List; - -import org.springframework.core.convert.converter.Converter; +import java.util.function.Function; /** * Default implementation of {@link Slice}. @@ -70,7 +69,7 @@ public class SliceImpl extends Chunk { * @see org.springframework.data.domain.Slice#transform(org.springframework.core.convert.converter.Converter) */ @Override - public Slice map(Converter converter) { + public Slice map(Function converter) { return new SliceImpl<>(getConvertedContent(converter), pageable, hasNext); } diff --git a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java index 1cc382141..200d7ed26 100644 --- a/src/main/java/org/springframework/data/repository/query/ResultProcessor.java +++ b/src/main/java/org/springframework/data/repository/query/ResultProcessor.java @@ -134,7 +134,7 @@ public class ResultProcessor { ChainingConverter converter = ChainingConverter.of(type.getReturnedType(), preparingConverter).and(this.converter); if (source instanceof Slice && method.isPageQuery() || method.isSliceQuery()) { - return (T) ((Slice) source).map(converter); + return (T) ((Slice) source).map(converter::convert); } if (source instanceof Collection && method.isCollectionQuery()) { diff --git a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java index 6ddf4f988..f54e4ae8d 100644 --- a/src/main/java/org/springframework/data/repository/query/parser/PartTree.java +++ b/src/main/java/org/springframework/data/repository/query/parser/PartTree.java @@ -177,7 +177,7 @@ public class PartTree implements Streamable { * @return the iterable {@link Part}s */ public Streamable getParts() { - return Streamable.of(this.stream().flatMap(OrPart::stream).collect(Collectors.toList())); + return flatMap(OrPart::stream); } /** @@ -187,10 +187,7 @@ public class PartTree implements Streamable { * @return */ public Streamable getParts(Type type) { - - return Streamable.of(getParts().stream()// - .filter(part -> part.getType().equals(type))// - .collect(Collectors.toList())); + return getParts().filter(part -> part.getType().equals(type)); } /* diff --git a/src/main/java/org/springframework/data/util/LazyStreamable.java b/src/main/java/org/springframework/data/util/LazyStreamable.java new file mode 100644 index 000000000..812409631 --- /dev/null +++ b/src/main/java/org/springframework/data/util/LazyStreamable.java @@ -0,0 +1,52 @@ +/* + * 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.Value; + +import java.util.Iterator; +import java.util.function.Supplier; +import java.util.stream.Stream; + +/** + * Lazy implementation of {@link Streamable} obtains a {@link Stream} from a given {@link Supplier}. + * + * @author Oliver Gierke + * @since 2.0 + */ +@Value(staticConstructor = "of") +class LazyStreamable implements Streamable { + + private final Supplier> stream; + + /* + * (non-Javadoc) + * @see java.lang.Iterable#iterator() + */ + @Override + public Iterator iterator() { + return stream().iterator(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.util.Streamable#stream() + */ + @Override + public Stream stream() { + return stream.get(); + } +} diff --git a/src/main/java/org/springframework/data/util/Streamable.java b/src/main/java/org/springframework/data/util/Streamable.java index 1ea612231..ae6d30f4c 100644 --- a/src/main/java/org/springframework/data/util/Streamable.java +++ b/src/main/java/org/springframework/data/util/Streamable.java @@ -17,6 +17,9 @@ package org.springframework.data.util; import java.util.Arrays; import java.util.Collections; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -28,17 +31,9 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Christoph Strobl */ +@FunctionalInterface public interface Streamable extends Iterable { - /** - * Creates a non-parallel {@link Stream} of the underlying {@link Iterable}. - * - * @return will never be {@literal null}. - */ - default Stream stream() { - return StreamSupport.stream(spliterator(), false); - } - /** * Returns an empty {@link Streamable}. * @@ -71,4 +66,59 @@ public interface Streamable extends Iterable { return iterable::iterator; } + + static Streamable of(Supplier> supplier) { + return LazyStreamable.of(supplier); + } + + /** + * Creates a non-parallel {@link Stream} of the underlying {@link Iterable}. + * + * @return will never be {@literal null}. + */ + default Stream stream() { + return StreamSupport.stream(spliterator(), false); + } + + /** + * Returns a new {@link Streamable} that will apply the given {@link Function} to the current one. + * + * @param mapper must not be {@literal null}. + * @return + * @see Stream#map(Function) + */ + default Streamable map(Function mapper) { + + Assert.notNull(mapper, "Mapping function must not be null!"); + + return Streamable.of(() -> stream().map(mapper)); + } + + /** + * Returns a new {@link Streamable} that will apply the given {@link Function} to the current one. + * + * @param mapper must not be {@literal null}. + * @return + * @see Stream#flatMap(Function) + */ + default Streamable flatMap(Function> mapper) { + + Assert.notNull(mapper, "Mapping function must not be null!"); + + return Streamable.of(() -> stream().flatMap(mapper)); + } + + /** + * Returns a new {@link Streamable} that will apply the given filter {@link Predicate} to the current one. + * + * @param predicate must not be {@literal null}. + * @return + * @see Stream#filter(Predicate) + */ + default Streamable filter(Predicate predicate) { + + Assert.notNull(predicate, "Filter predicate must not be null!"); + + return Streamable.of(() -> stream().filter(predicate)); + } }