@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));
}