class AnnotatedMultiPropertyPathDetector extends TypedVisitor<TypeDefBuilder> {

  protected static final String DOT = ".";
  protected static final String STATUS = ".status.";

  private final String prefix;
  private final String annotationName;
  private final List<Property> parents;
  private final Map<String, Property> properties;
  private final Deque<Runnable> toRun;

  public AnnotatedMultiPropertyPathDetector(String prefix, String annotationName) {
    this(prefix, annotationName, new ArrayList<>(), new HashMap<>(), new ArrayDeque<>());
  }

  public AnnotatedMultiPropertyPathDetector(String prefix, String annotationName, List<Property> parents,
      Map<String, Property> properties, Deque<Runnable> toRun) {
    this.prefix = prefix;
    this.annotationName = annotationName;
    this.parents = parents;
    this.properties = properties;
    this.toRun = toRun;
  }

  private boolean excludePropertyProcessing(Property p) {
    return p.getAnnotations().stream()
        .anyMatch(ann -> ann.getClassRef().getFullyQualifiedName().equals(ANNOTATION_JSON_IGNORE));
  }

  @Override
  public void visit(TypeDefBuilder builder) {<FILL_FUNCTION_BODY>}

  public Set<String> getPaths() {
    return properties.keySet();
  }

  public Map<String, Property> getProperties() {
    return properties;
  }
}

    TypeDef type = builder.build();
    final List<Property> props = type.getProperties();
    for (Property p : props) {
      if (parents.contains(p)) {
        continue;
      }

      List<Property> newParents = new ArrayList<>(parents);
      boolean match = p.getAnnotations().stream().anyMatch(a -> a.getClassRef().getName().equals(annotationName));
      if (match) {
        newParents.add(p);
        this.properties
            .put(newParents.stream().map(Property::getName).collect(Collectors.joining(DOT, prefix, "")), p);
      }
    }

    props.stream().filter(p -> p.getTypeRef() instanceof ClassRef).forEach(p -> {
      if (!parents.contains(p) && !excludePropertyProcessing(p)) {
        ClassRef classRef = (ClassRef) p.getTypeRef();
        TypeDef propertyType = Types.typeDefFrom(classRef);
        if (!propertyType.isEnum() && !classRef.getPackageName().startsWith("java.")) {
          List<Property> newParents = new ArrayList<>(parents);
          newParents.add(p);
          toRun.add(() -> new TypeDefBuilder(propertyType)
              .accept(new AnnotatedMultiPropertyPathDetector(prefix, annotationName, newParents, properties, toRun)));
        }
      }
    });

    if (parents.isEmpty()) {
      while (!toRun.isEmpty()) {
        toRun.pop().run();
      }
    }
  
<no_super_class>