package org.infinispan.stream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import org.infinispan.commons.marshall.Externalizer;
import org.infinispan.commons.marshall.SerializeWith;
import org.infinispan.util.function.SerializableSupplier;
/**
* Helper class designed to be used to create a serializable Collector for use with
* {@link org.infinispan.CacheStream#collect(Collector)} from a supplier of a collector. The problem is that the
* standard {@link java.util.stream.Collectors} class doesn't provide Serializable Collectors and no way to extend
* their functionality, so this class is used instead.
*/
public class CacheCollectors {
private CacheCollectors() { }
/**
* Creates a collector that is serializable and will upon usage create a collector using the serializable supplier
* provided by the user.
* @param supplier The supplier to crate the collector that is specifically serializable
* @param <T> The input type of the collector
* @param <R> The resulting type of the collector
* @return the collector which is serializable
* @see SerializableSupplier
*/
public static <T, R> Collector<T, ?, R> serializableCollector(SerializableSupplier<Collector<T, ?, R>> supplier) {
return new CollectorSupplier<>(supplier);
}
/**
* Similar to {@link CacheCollectors#serializableCollector(SerializableSupplier)} except that the supplier provided
* must be marshable through ISPN marshalling techniques. Note this is not detected until runtime.
* @param supplier The marshallable supplier of collectors
* @param <T> The input type of the collector
* @param <R> The resulting type of the collector
* @return the collector which is serializable
* @see Externalizer
* @see org.infinispan.commons.marshall.AdvancedExternalizer
*/
public static <T, R> Collector<T, ?, R> collector(Supplier<Collector<T, ?, R>> supplier) {
return new CollectorSupplier<>(supplier);
}
@SerializeWith(value = CollectorSupplier.CollectorSupplierExternalizer.class)
private static final class CollectorSupplier<T, R> implements Collector<T, Object, R> {
private final Supplier<Collector<T, ?, R>> supplier;
private transient Collector<T, Object, R> collector;
private Collector<T, Object, R> getCollector() {
if (collector == null) {
collector = (Collector<T, Object, R>) supplier.get();
}
return collector;
}
CollectorSupplier(Supplier<Collector<T, ?, R>> supplier) {
this.supplier = supplier;
}
@Override
public Supplier<Object> supplier() {
return getCollector().supplier();
}
@Override
public BiConsumer<Object, T> accumulator() {
return getCollector().accumulator();
}
@Override
public BinaryOperator<Object> combiner() {
return getCollector().combiner();
}
@Override
public Function<Object, R> finisher() {
return getCollector().finisher();
}
@Override
public Set<Characteristics> characteristics() {
return getCollector().characteristics();
}
public static final class CollectorSupplierExternalizer implements Externalizer<CollectorSupplier<?, ?>> {
@Override
public void writeObject(ObjectOutput output, CollectorSupplier object) throws IOException {
output.writeObject(object.supplier);
}
@Override
public CollectorSupplier readObject(ObjectInput input) throws IOException, ClassNotFoundException {
return new CollectorSupplier((Supplier<Collector>) input.readObject());
}
}
}
}