package tc.oc.commons.core.inspect; import java.util.function.Supplier; import tc.oc.commons.core.stream.BiStream; public interface InspectableProperty { String name(); Object value(Inspectable inspectable) throws Throwable; default Inspection options() { return Inspection.defaults(); } default Object valueWrappingException(Inspectable inspectable) throws InspectionException { try { return value(inspectable); } catch(Throwable e) { throw new InspectionException(e.getClass().getSimpleName() + " inspecting '" + name() + "' property: " + e.getMessage(), e); } } default Object valueOrException(Inspectable inspectable) { try { return valueWrappingException(inspectable); } catch(InspectionException e) { return e; } } default BiStream<InspectableProperty, Object> flatValues(Inspectable inspectable) { Object value = options().unwrap(valueOrException(inspectable)); if(options().inline() && value instanceof Inspectable) { final Inspectable child = (Inspectable) value; return BiStream.from(child.inspectableProperties() .flatMap(prop -> prop.flatValues(child))); } if(options().isPresent(value)) { return BiStream.of(this, value); } return BiStream.empty(); } static InspectableProperty of(String name, Object value) { return new InspectableProperty() { @Override public String name() { return name; } @Override public Object value(Inspectable inspectable) throws InspectionException { return value; } }; } static InspectableProperty reading(String name, Supplier<?> value) { return new InspectableProperty() { @Override public String name() { return name; } @Override public Object value(Inspectable inspectable) throws InspectionException { return value.get(); } }; } }