package com.codepoetics.phantompojo; import java.util.function.BiFunction; import java.util.function.Function; import java.util.function.Supplier; import java.util.function.UnaryOperator; public interface Lens<P, T> { T get(P pojo); P set(P pojo, T newValue); default P update(P pojo, UnaryOperator<T> updater) { return set(pojo, updater.apply(get(pojo))); } static <P, T> Lens<P, T> on(Function<P, T> getter, BiFunction<P, T, P> setter) { return new Lens<P, T>() { @Override public T get(P pojo) { return getter.apply(pojo); } @Override public P set(P pojo, T newValue) { return setter.apply(pojo, newValue); } }; } default <T2> Lens<P, T2> andThen(Lens<T, T2> next) { return on(p -> next.get(get(p)), (p, t2) -> set(p, next.set(get(p), t2))); } static <T, B extends Supplier<P>, P extends PhantomPojo<B>> Lens<P, T> onPhantom(Function<P, T> getter, BiFunction<B, T, B> updater) { return on(getter, (p, t) -> updater.apply(p.update(), t).get()); } }