package tc.oc.commons.core.inspect; import java.lang.reflect.Array; import java.util.Collection; import java.util.Map; import java.util.Optional; import com.google.common.collect.Maps; import tc.oc.commons.core.util.ArrayUtils; import tc.oc.commons.core.util.Chain; import tc.oc.commons.core.util.Lazy; public class Inspection { private static final Inspection DEFAULTS = new Inspection(true, false, true, true, false); public static Inspection defaults() { return DEFAULTS; } private final boolean optional, brief, deep, quote, inline; public Inspection(Inspectable.Inspect annotation) { this(annotation.optional(), annotation.brief(), annotation.deep(), annotation.quote(), annotation.inline()); } public Inspection(boolean optional, boolean brief, boolean deep, boolean quote, boolean inline) { this.optional = optional; this.brief = brief; this.deep = deep; this.quote = quote; this.inline = inline; } public boolean optional() { return optional; } public boolean brief() { return brief; } public boolean deep() { return deep; } public boolean quote() { return quote; } public boolean inline() { return inline; } public boolean isPresent(Object value) { if(!optional()) return true; if(value == null) return false; if(value instanceof Optional && !((Optional) value).isPresent()) return false; if(value instanceof Collection && ((Collection) value).isEmpty()) return false; if(value instanceof Map && ((Map) value).isEmpty()) return false; if(value.getClass().isArray() && Array.getLength(value) == 0) return false; return true; } public boolean isCollection(Object value) { return deep() && value != null && (value instanceof Collection || value.getClass().isArray()); } public Collection<?> asCollection(Object value) { if(value instanceof Collection) return (Collection<?>) value; if(value != null && value.getClass().isArray()) return ArrayUtils.asList(value); throw new IllegalArgumentException("Not a collection"); } public Object unwrap(Object value) { if(deep()) { if(value instanceof Optional && ((Optional) value).isPresent()) { return unwrap(((Optional) value).get()); } if(value instanceof Lazy) { return unwrap(((Lazy) value).get()); } } return value; } public <R> R inspect(Inspector<R> inspector, Object value, Chain<Object> visited) { if(visited.containsIdentity(value)) { return inspector.cycle(value, visited, this); } else if(value instanceof InspectionException) { return inspector.exception((InspectionException) value, this); } else if(value instanceof Optional && ((Optional) value).isPresent()) { return inspect(inspector, ((Optional) value).get(), visited); } else if(value instanceof Map) { final Map<?, ?> map = (Map<?, ?>) value; return inspector.map(map, map.entrySet() .stream() .map(e -> Maps.immutableEntry(inspect(inspector, e.getKey(), visited.push(map)), inspect(inspector, e.getValue(), visited.push(map)))), this); } else if(isCollection(value)) { final Collection<?> collection = asCollection(value); return inspector.collection(collection, collection.stream().map(e -> inspect(inspector, e, visited)), this); } else if(value instanceof Inspectable) { final Inspectable inspectable = (Inspectable) value; if(brief()) { return inspector.reference(inspectable, this); } else { return inspector.inspectable(inspectable, inspectable.inspectProperties(inspector, visited), this); } } else { return inspector.scalar(value, this); } } }