
jsonvalues.Lens Maven / Gradle / Ivy
package jsonvalues;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import static java.util.Objects.requireNonNull;
/**
* A Lens is an optic that can be seen as a pair of functions:
{@code
- get: S => O i.e. from an S, we can extract an O
- set: (O, S) => S i.e. from an S and a O, we obtain a S. Unless a prism, to go back to S we need another S.
}
* Typically a Lens can be defined between a Product (e.g. record, tuple) and one of its component.
* Given a lens there are essentially three things you might want to do:
* -view the subpart
* -modify the whole by changing the subpart
* -combine this lens with another lens to look even deeper
*
* @param the source of a lens
* @param the target of a lens
*/
public class Lens {
/**
* function to view the part
*/
public final Function get;
/**
* function to modify the whole by setting the subpart
*/
public final Function> set;
/**
find if the target satisfies the predicate
*/
public final Function,Function>> find;
/**
check if there is a target and it satisfies the predicate
*/
public final Function,Predicate> exists;
/**
* function to modify the whole by modifying the subpart with a function
*/
public final Function, Function> modify;
Lens(final Function get,
final Function> set) {
this.set = set;
this.get = get;
this.modify = f -> json -> set.apply(f.apply(get.apply(json))).apply(json);
this.find = predicate -> s -> predicate.test(get.apply(s)) ?
Optional.of((get.apply(s))) :
Optional.empty();
this.exists = predicate -> s -> predicate.test(get.apply(s));
}
/**
Composing a Lens and a Prism returns and Optional
@param prism A Prism from the focus of the lens to the new focus of the Optional
@param the type of the new focus of the Optional
@return an Optional
*/
public Option compose(final Prism prism) {
return new Option<>(json -> requireNonNull(prism).getOptional.apply(get.apply(json)),
value -> json -> set.apply(prism.reverseGet.apply(value))
.apply(json)
);
}
/**
Compose this lens with another one
@param other the other lens
@param the type of the focus on the new lens
@return a new Lens
*/
public Lens compose(final Lens other){
return new Lens<>(this.get.andThen(other.get),
b-> s -> {
O o = other.set.apply(b).apply(this.get.apply(s));
return this.set.apply(o).apply(s);
}
);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy