|
|
@@ -2,7 +2,8 @@ package net.ranides.assira.reflection.walker;
|
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
|
-import net.ranides.assira.reflection.*;
|
|
|
+import net.ranides.assira.reflection.IClass;
|
|
|
+import net.ranides.assira.reflection.ResolveContext;
|
|
|
import net.ranides.assira.reflection.walker.ObjectVisitor.PrintVisitor;
|
|
|
import net.ranides.assira.reflection.walker.WalkerContexts.ArrayContext;
|
|
|
import net.ranides.assira.reflection.walker.WalkerContexts.ObjectContext;
|
|
|
@@ -22,12 +23,13 @@ import java.util.HashMap;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.function.BiConsumer;
|
|
|
+import java.util.function.BiFunction;
|
|
|
import java.util.function.Consumer;
|
|
|
import java.util.function.Function;
|
|
|
|
|
|
public class WalkerRules {
|
|
|
|
|
|
- public static final WalkerRules DEFAULT = new WalkerRules()
|
|
|
+ public static final WalkerRules DEFAULT = new Builder()
|
|
|
.tag("PATH", "{id,text,4}.{namePath,text,-50}")
|
|
|
.rule()
|
|
|
.match(ObjectContext::isVisited)
|
|
|
@@ -43,11 +45,11 @@ public class WalkerRules {
|
|
|
.term("{PATH} {actual.shortname} = '{value}'")
|
|
|
.rule()
|
|
|
.match(byte[].class)
|
|
|
- .text(ctx -> FormatHex.format(ctx.value()))
|
|
|
+ .format(ctx -> FormatHex.format(ctx.value()))
|
|
|
.term("{PATH} {actual.shortname} = '{value}'")
|
|
|
.rule()
|
|
|
.match(char[].class)
|
|
|
- .text(ctx -> String.valueOf(ctx.value()))
|
|
|
+ .format(ctx -> String.valueOf(ctx.value()))
|
|
|
.term("{PATH} {actual.shortname} = '{value}'")
|
|
|
.rule()
|
|
|
.match(ArrayContext.class::isInstance)
|
|
|
@@ -68,181 +70,231 @@ public class WalkerRules {
|
|
|
.rule()
|
|
|
.match(Object.class)
|
|
|
.hint("{PATH} {actual.shortname} = {value}")
|
|
|
- ;
|
|
|
+ .prepare();
|
|
|
|
|
|
- private final Map<String, ResolveFormat> tags = new HashMap<>();
|
|
|
+ private final Map<String, ResolveFormat> tags;
|
|
|
+ private final List<RuleEntry> rules;
|
|
|
|
|
|
- private final List<RuleEntry> rules = new ArrayList<>();
|
|
|
+ private WalkerRules(Map<String, ResolveFormat> tags, List<RuleEntry> rules) {
|
|
|
+ this.tags = new HashMap<>(tags);
|
|
|
+ this.rules = new ArrayList<>(rules);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static Builder builder() {
|
|
|
+ return new Builder();
|
|
|
+ }
|
|
|
|
|
|
public PrintVisitor visitor(OutputStream target) {
|
|
|
return visitor(new OutputStreamWriter(target, Charsets.UTF8));
|
|
|
}
|
|
|
|
|
|
public PrintVisitor visitor(Writer target) {
|
|
|
- return new PrintVisitor(new PrintWriter(target)){
|
|
|
- @Override
|
|
|
- public boolean visitRoot(ObjectContext<?> context) {
|
|
|
- context.custom(tags);
|
|
|
- return true;
|
|
|
+ return new RuleVisitor(target);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static class Builder {
|
|
|
+
|
|
|
+ private final Map<String, ResolveFormat> tags = new HashMap<>();
|
|
|
+ private final List<RuleEntry> rules = new ArrayList<>();
|
|
|
+
|
|
|
+ public WalkerRules prepare() {
|
|
|
+ return new WalkerRules(tags, rules);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Builder tag(String name, String value) {
|
|
|
+ this.tags.put(name, ResolveFormat.compile(value));
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public RootRule rule() {
|
|
|
+ return new RootRule();
|
|
|
+ }
|
|
|
+
|
|
|
+ public Builder rules(WalkerRules parent) {
|
|
|
+ this.tags.putAll(parent.tags);
|
|
|
+ this.rules.addAll(parent.rules);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ public abstract class AbstractRule<F> {
|
|
|
+
|
|
|
+ protected final List<RulePredicate<?>> predicates;
|
|
|
+
|
|
|
+ protected Consumer<ObjectContext<F>> formatter = x -> { };
|
|
|
+
|
|
|
+ protected AbstractRule(List<RulePredicate<?>> predicates) {
|
|
|
+ this.predicates = predicates;
|
|
|
}
|
|
|
|
|
|
- @Override
|
|
|
- public boolean visitObject(ObjectContext<?> context) {
|
|
|
- for (RuleEntry rule : rules) {
|
|
|
- if(rule.test(context)) {
|
|
|
- return rule.consume(this, context);
|
|
|
- }
|
|
|
- }
|
|
|
- return true;
|
|
|
+ public Builder text(String text) {
|
|
|
+ ResolveFormat fmt = ResolveFormat.compile(text);
|
|
|
+ return text((target, ctx) -> fmt.format(ctx));
|
|
|
}
|
|
|
- };
|
|
|
- }
|
|
|
|
|
|
- public WalkerRules inherit(WalkerRules parent) {
|
|
|
- this.tags.putAll(parent.tags);
|
|
|
- this.rules.addAll(parent.rules);
|
|
|
- return this;
|
|
|
- }
|
|
|
+ public Builder text(Function<ObjectContext<F>, String> handler) {
|
|
|
+ return text((target, ctx) -> handler.apply(ctx));
|
|
|
+ }
|
|
|
|
|
|
- public WalkerRules tag(String name, String value) {
|
|
|
- this.tags.put(name, ResolveFormat.compile(value));
|
|
|
- return this;
|
|
|
- }
|
|
|
+ public Builder text(BiFunction<PrintVisitor, ObjectContext<F>, String> handler) {
|
|
|
+ return rule(predicates, RuleType.FORMAT, asHandler((v,c) -> c.custom("value", handler.apply(v, c))));
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderRoot rule() {
|
|
|
- return new RuleBuilderRoot();
|
|
|
- }
|
|
|
+ public Builder hint(String text) {
|
|
|
+ ResolveFormat fmt = ResolveFormat.compile(text);
|
|
|
+ return hint((target, ctx) -> target.writer().println(fmt.format(ctx)));
|
|
|
+ }
|
|
|
|
|
|
- public abstract class RuleBuilder<F> {
|
|
|
+ public Builder hint(Consumer<ObjectContext<F>> handler) {
|
|
|
+ return hint((target, ctx) -> handler.accept(ctx));
|
|
|
+ }
|
|
|
|
|
|
- protected final List<RulePredicate<?>> predicates;
|
|
|
+ public Builder hint(BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
+ return rule(predicates, RuleType.HINT, asHandler(handler));
|
|
|
+ }
|
|
|
|
|
|
- protected Consumer<ObjectContext<F>> formatter = x -> { };
|
|
|
+ public Builder term(String text) {
|
|
|
+ ResolveFormat fmt = ResolveFormat.compile(text);
|
|
|
+ return term((target, ctx) -> target.writer().println(fmt.format(ctx)));
|
|
|
+ }
|
|
|
|
|
|
- protected RuleBuilder(List<RulePredicate<?>> predicates) {
|
|
|
- this.predicates = predicates;
|
|
|
- }
|
|
|
+ public Builder term(Consumer<ObjectContext<F>> handler) {
|
|
|
+ return term((target, ctx) -> handler.accept(ctx));
|
|
|
+ }
|
|
|
|
|
|
- public WalkerRules hint(String text) {
|
|
|
- ResolveFormat fmt = ResolveFormat.compile(text);
|
|
|
- return hint((target, ctx) -> target.writer().println(fmt.format(ctx)));
|
|
|
- }
|
|
|
+ public Builder term(BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
+ return rule(predicates, RuleType.TERM, asHandler(handler));
|
|
|
+ }
|
|
|
|
|
|
- public WalkerRules hint(Consumer<ObjectContext<F>> handler) {
|
|
|
- return hint((target, ctx) -> handler.accept(ctx));
|
|
|
- }
|
|
|
+ private RuleHandler<F> asHandler(BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
+ return (target, ctx) -> {
|
|
|
+ formatter.accept(ctx);
|
|
|
+ handler.accept(target, ctx);
|
|
|
+ };
|
|
|
+ }
|
|
|
|
|
|
- public WalkerRules hint(BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
- return rule(predicates, asHandler(true, handler));
|
|
|
- }
|
|
|
+ private <U> Builder rule(List<RulePredicate<?>> predicates, RuleType type, RuleHandler<U> handler) {
|
|
|
+ predicates.forEach(predicate -> rules.add(new RuleEntry(predicate, handler, type)));
|
|
|
+ return Builder.this;
|
|
|
+ }
|
|
|
|
|
|
- public WalkerRules term(String text) {
|
|
|
- ResolveFormat fmt = ResolveFormat.compile(text);
|
|
|
- return term((target, ctx) -> target.writer().println(fmt.format(ctx)));
|
|
|
}
|
|
|
|
|
|
- public WalkerRules term(Consumer<ObjectContext<F>> handler) {
|
|
|
- return term((target, ctx) -> handler.accept(ctx));
|
|
|
- }
|
|
|
+ public class RootRule extends AbstractRule<Object> {
|
|
|
|
|
|
- public WalkerRules term(BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
- return rule(predicates, asHandler(false, handler));
|
|
|
- }
|
|
|
+ public RootRule() {
|
|
|
+ super(new ArrayList<>());
|
|
|
+ }
|
|
|
|
|
|
- private RuleHandler<F> asHandler(boolean follow, BiConsumer<PrintVisitor, ObjectContext<F>> handler) {
|
|
|
- return (target, ctx) -> {
|
|
|
- formatter.accept(ctx);
|
|
|
- handler.accept(target, ctx);
|
|
|
- return follow;
|
|
|
- };
|
|
|
- }
|
|
|
+ public RootRule format(String text) {
|
|
|
+ return format(ResolveFormat.compile(text)::format);
|
|
|
+ }
|
|
|
|
|
|
- private <U> WalkerRules rule(List<RulePredicate<?>> predicates, RuleHandler<U> handler) {
|
|
|
- predicates.forEach(predicate -> rules.add(new RuleEntry(predicate, handler)));
|
|
|
- return WalkerRules.this;
|
|
|
- }
|
|
|
+ public RootRule format(Function<ObjectContext<Object>, String> formatter) {
|
|
|
+ this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ public <T> TypeRule<T> match(Class<T> type) {
|
|
|
+ return match(IClass.typeinfo(type));
|
|
|
+ }
|
|
|
|
|
|
- public class RuleBuilderRoot extends RuleBuilder<Object> {
|
|
|
+ public <T> TypeRule<T> match(IClass<T> type) {
|
|
|
+ predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
+ return new TypeRule<>(this);
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderRoot() {
|
|
|
- super(new ArrayList<>());
|
|
|
- }
|
|
|
+ public MoreRule match(RulePredicate<?> predicate) {
|
|
|
+ predicates.add(predicate);
|
|
|
+ return new MoreRule(this);
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderRoot text(Function<ObjectContext<Object>, String> formatter) {
|
|
|
- this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
- return this;
|
|
|
}
|
|
|
|
|
|
- public <T> RuleBuilderType<T> match(Class<T> type) {
|
|
|
- return match(IClass.typeinfo(type));
|
|
|
- }
|
|
|
+ public class TypeRule<F> extends AbstractRule<F> {
|
|
|
|
|
|
- public <T> RuleBuilderType<T> match(IClass<T> type) {
|
|
|
- predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
- return new RuleBuilderType<>(this);
|
|
|
- }
|
|
|
+ public TypeRule(AbstractRule<?> source) {
|
|
|
+ super(source.predicates);
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore match(RulePredicate<?> predicate){
|
|
|
- predicates.add(predicate);
|
|
|
- return new RuleBuilderMore(this);
|
|
|
- }
|
|
|
+ public TypeRule<F> format(String text) {
|
|
|
+ return format(ResolveFormat.compile(text)::format);
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ public TypeRule<F> format(Function<ObjectContext<F>, String> formatter) {
|
|
|
+ this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
- public class RuleBuilderType<F> extends RuleBuilder<F> {
|
|
|
+ public MoreRule match(Class<?> type) {
|
|
|
+ return match(IClass.typeinfo(type));
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderType(RuleBuilder<?> source) {
|
|
|
- super(source.predicates);
|
|
|
- }
|
|
|
+ public MoreRule match(IClass<?> type) {
|
|
|
+ predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
+ return new MoreRule(this);
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderType<F> text(Function<ObjectContext<F>, String> formatter) {
|
|
|
- this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
- return this;
|
|
|
- }
|
|
|
+ public MoreRule match(RulePredicate<?> predicate) {
|
|
|
+ predicates.add(predicate);
|
|
|
+ return new MoreRule(this);
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore match(Class<?> type) {
|
|
|
- return match(IClass.typeinfo(type));
|
|
|
}
|
|
|
|
|
|
- public RuleBuilderMore match(IClass<?> type) {
|
|
|
- predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
- return new RuleBuilderMore(this);
|
|
|
- }
|
|
|
+ public class MoreRule extends AbstractRule<Object> {
|
|
|
|
|
|
- public RuleBuilderMore match(RulePredicate<?> predicate) {
|
|
|
- predicates.add(predicate);
|
|
|
- return new RuleBuilderMore(this);
|
|
|
- }
|
|
|
+ public MoreRule(AbstractRule<?> source) {
|
|
|
+ super(source.predicates);
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
+ public MoreRule format(String text) {
|
|
|
+ return format(ResolveFormat.compile(text)::format);
|
|
|
+ }
|
|
|
|
|
|
- public class RuleBuilderMore extends RuleBuilder<Object> {
|
|
|
+ public MoreRule format(Function<ObjectContext<Object>, String> formatter) {
|
|
|
+ this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore(RuleBuilder<?> source) {
|
|
|
- super(source.predicates);
|
|
|
- }
|
|
|
+ public MoreRule match(Class<?> type) {
|
|
|
+ return match(IClass.typeinfo(type));
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore text(Function<ObjectContext<Object>, String> formatter) {
|
|
|
- this.formatter = ctx -> ctx.custom("value", formatter.apply(ctx));
|
|
|
- return this;
|
|
|
- }
|
|
|
+ public MoreRule match(IClass<?> type) {
|
|
|
+ predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore match(Class<?> type) {
|
|
|
- return match(IClass.typeinfo(type));
|
|
|
- }
|
|
|
+ public MoreRule match(RulePredicate<?> predicate) {
|
|
|
+ predicates.add(predicate);
|
|
|
+ return this;
|
|
|
+ }
|
|
|
|
|
|
- public RuleBuilderMore match(IClass<?> type) {
|
|
|
- predicates.add(ctx -> ctx.isSubclass(type));
|
|
|
- return this;
|
|
|
}
|
|
|
|
|
|
- public RuleBuilderMore match(RulePredicate<?> predicate) {
|
|
|
- predicates.add(predicate);
|
|
|
- return this;
|
|
|
+ }
|
|
|
+
|
|
|
+ private class RuleVisitor extends PrintVisitor {
|
|
|
+
|
|
|
+ public RuleVisitor(Writer target) {
|
|
|
+ super(new PrintWriter(target), ResolveContext.of(tags));
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public boolean visitObject(ObjectContext<?> context) {
|
|
|
+ for (RuleEntry rule : rules) {
|
|
|
+ if(rule.test(context)) {
|
|
|
+ rule.consume(this, context);
|
|
|
+ switch (rule.type) {
|
|
|
+ case HINT: return true;
|
|
|
+ case TERM: return false;
|
|
|
+ case FORMAT:
|
|
|
+ // continue processing
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
|
|
@@ -250,21 +302,26 @@ public class WalkerRules {
|
|
|
private static class RuleEntry {
|
|
|
private final RulePredicate predicate;
|
|
|
private final RuleHandler consumer;
|
|
|
+ private final RuleType type;
|
|
|
|
|
|
public boolean test(ObjectContext<?> context) {
|
|
|
return predicate.test(context);
|
|
|
}
|
|
|
|
|
|
- public boolean consume(PrintVisitor visitor, ObjectContext<?> context) {
|
|
|
- return consumer.test(visitor, context);
|
|
|
+ public void consume(PrintVisitor visitor, ObjectContext<?> context) {
|
|
|
+ consumer.apply(visitor, context);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ private enum RuleType {
|
|
|
+ TERM, HINT, FORMAT
|
|
|
+ }
|
|
|
+
|
|
|
public interface RulePredicate<U> {
|
|
|
boolean test(ObjectContext<U> context);
|
|
|
}
|
|
|
|
|
|
public interface RuleHandler<U> {
|
|
|
- boolean test(PrintVisitor printVisitor, ObjectContext<U> context);
|
|
|
+ void apply(PrintVisitor printVisitor, ObjectContext<U> context);
|
|
|
}
|
|
|
}
|