Attrs { public static String toJson(AcceptingVisitor composite, ClassNameMapper classNameMapper) { return toJson(composite, classNameMapper::toName); }  static Map<String, Object> toMap(AcceptingVisitor composite); static Map<String, Object> toMap(
      AcceptingVisitor composite, Function<Object, String> classToName); static E fromMap(
      Class<? extends E> clazz, Map<String, Object> map); static E fromMap(
      Class<? extends E> clazz, Map<String, Object> map, Function<String, Object> nameToClass); static Map<String, Object> extract(
      AcceptingVisitor instance, Function<Object, String> classToName); static Map<String, Object> extract(AcceptingVisitor instance); static E populate(E instance, Map<String, Object> map); static E populate(
      E instance, Map<String, Object> map, Function<String, Object> nameToClass); static String toJson(AcceptingVisitor composite, ClassNameMapper classNameMapper); static String toJson(AcceptingVisitor composite, Function<Object, String> classToName);  }
@Test public void testCustomDictionary() { class Entry implements AcceptingVisitor { String match; String[] tokens; @Override public void accept(AttrVisitor visitor) { AttrString a1 = AttrString.builder().defaultValue(match); visitor.visit("match", a1); this.match = a1.get(); AttrStringArray a2 = AttrStringArray.builder().defaultValue(tokens); visitor.visit("tokens", a2); tokens = a2.get(); } } class AdHocDict extends AttrComposite { List<Entry> entries; { attributes.register( "entries", AttrObjectArray.builder(Entry.class, () -> new Entry()) .getset(() -> entries, (list) -> entries = list) .defaultValue(null)); } } class Clazz extends AttrComposite { AdHocDict adHocDict = new AdHocDict(); { attributes.register( "adhoc", AttrObject.builder(AdHocDict.class) .getset(() -> adHocDict, (v) -> adHocDict = v) .defaultValue(() -> new AdHocDict())); } } Entry entry = new Entry(); entry.match = "e"; entry.tokens = new String[] {"foo", "bar"}; Clazz ob = new Clazz(); ob.adHocDict.entries = Arrays.asList(entry, entry); System.out.println(Attrs.toJson(ob, JvmNameMapper.INSTANCE)); }