package org.codefx.libfx.collection.transform; import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.function.Function; /** * Builder for {@link TransformingCollection}s, {@link TransformingSet}s and {@link TransformingList}s. * <p> * A builder can be obtained by calling {@link #forInnerAndOuterType(Class, Class) forInnerAndOuterType} or * {@link #forInnerAndOuterTypeUnknown()}. The building methods {@code transform...} can only be called after * transformations from inner to outer elements and vice versa have been set. * * @param <I> * the inner type of the created transforming collection, i.e. the type of the elements contained in the * wrapped/inner collection * @param <O> * the outer type of the created transforming collection, i.e. the type of elements appearing to be in the * created collection */ public class TransformingCollectionBuilder<I, O> { // #begin FIELDS private final Class<? super O> outerTypeToken; private final Class<? super I> innerTypeToken; private Function<? super I, ? extends O> transformToOuter; private Function<? super O, ? extends I> transformToInner; // #end FIELDS // #begin CONSTRUCTION private TransformingCollectionBuilder(Class<? super I> innerTypeToken, Class<? super O> outerTypeToken) { Objects.requireNonNull(innerTypeToken, "The argument 'innerTypeToken' must not be null."); Objects.requireNonNull(outerTypeToken, "The argument 'outerTypeToken' must not be null."); this.outerTypeToken = outerTypeToken; this.innerTypeToken = innerTypeToken; } /** * Returns a new builder for the specified inner and outer type. * * @param <I> * the inner type of the created transforming collection, i.e. the type of the elements contained in the * wrapped/inner collection * @param <O> * the outer type of the created transforming collection, i.e. the type of elements appearing to be in * the created collection * @param innerTypeToken * the token for the inner type * @param outerTypeToken * the token for the outer type * @return a new builder */ public static <I, O> TransformingCollectionBuilder<I, O> forInnerAndOuterType( Class<? super I> innerTypeToken, Class<? super O> outerTypeToken) { return new TransformingCollectionBuilder<>(innerTypeToken, outerTypeToken); } /** * Returns a new builder for unknown inner and outer types. * <p> * This is equivalent to calling {@link #forInnerAndOuterType(Class, Class) forInnerAndOuterType(Object.class, * Object.class)}. To obtain a builder for {@code <I, O>} you will have to call * {@code TransformingCollectionBuilder.<I, O> forInnerAndOuterTypeUnknown()}. * * @param <I> * the inner type of the created transforming collection, i.e. the type of the elements contained in the * wrapped/inner collection * @param <O> * the outer type of the created transforming collection, i.e. the type of elements appearing to be in * the created collection * @return a new builder */ public static <I, O> TransformingCollectionBuilder<I, O> forInnerAndOuterTypeUnknown() { return forInnerAndOuterType(Object.class, Object.class); } // #end CONSTRUCTION // #begin SET FIELDS /** * Sets the transformation from inner to outer elements which will be used by the created collection. * * @param transformToOuter * transforms inner to outer elements * @return this builder */ public TransformingCollectionBuilder<I, O> toOuter(Function<? super I, ? extends O> transformToOuter) { Objects.requireNonNull(transformToOuter, "The argument 'transformToOuter' must not be null."); this.transformToOuter = transformToOuter; return this; } /** * Sets the transformation from outer to inner elements which will be used by the created collection. * * @param transformToInner * transforms outer to inner elements * @return this builder */ public TransformingCollectionBuilder<I, O> toInner(Function<? super O, ? extends I> transformToInner) { Objects.requireNonNull(transformToInner, "The argument 'transformToInner' must not be null."); this.transformToInner = transformToInner; return this; } // #end SET FIELDS // #begin BUILD /** * Creates a {@link TransformingCollection} which transforms/decorates the specified collection. * * @param collection * the collection to transform; will be the inner collection of the returned transformation * @return a new {@link TransformingCollection} */ public TransformingCollection<I, O> transformCollection(Collection<I> collection) { return new TransformingCollection<>( collection, innerTypeToken, outerTypeToken, transformToOuter, transformToInner); } /** * Creates a {@link TransformingSet} which transforms/decorates the specified set. * * @param set * the set to transform; will be the inner set of the returned transformation * @return a new {@link TransformingSet} */ public TransformingSet<I, O> transformSet(Set<I> set) { return new TransformingSet<>( set, innerTypeToken, outerTypeToken, transformToOuter, transformToInner); } /** * Creates a {@link TransformingList} which transforms/decorates the specified list. * * @param list * the list to transform; will be the inner list of the returned transformation * @return a new {@link TransformingList} */ public TransformingList<I, O> transformList(List<I> list) { return new TransformingList<>( list, innerTypeToken, outerTypeToken, transformToOuter, transformToInner); } // #end BUILD }