private static void parseSubHierarchy(Node parent, ClassHierarchyProto.Node n) {
    final Node parsed;
    if (n.hasPackageNode()) {
      parsed = new PackageNodeImpl(parent, n.getName(), n.getFullName());
    } else if (n.hasNamedParameterNode()) {
      ClassHierarchyProto.NamedParameterNode np = n.getNamedParameterNode();
      parsed =
          new NamedParameterNodeImpl<Object>(
              parent,
              n.getName(),
              n.getFullName(),
              np.getFullArgClassName(),
              np.getSimpleArgClassName(),
              np.getIsSet(),
              np.getIsList(),
              np.getDocumentation(),
              np.getShortName(),
              np.getInstanceDefaultList().toArray(new String[0]));
    } else if (n.hasClassNode()) {
      ClassHierarchyProto.ClassNode cn = n.getClassNode();
      List<ConstructorDef<?>> injectableConstructors = new ArrayList<>();
      List<ConstructorDef<?>> allConstructors = new ArrayList<>();

      for (ClassHierarchyProto.ConstructorDef injectable : cn.getInjectableConstructorsList()) {
        ConstructorDef<?> def = parseConstructorDef(injectable, true);
        injectableConstructors.add(def);
        allConstructors.add(def);
      }
      for (ClassHierarchyProto.ConstructorDef other : cn.getOtherConstructorsList()) {
        ConstructorDef<?> def = parseConstructorDef(other, false);
        allConstructors.add(def);
      }
      @SuppressWarnings("unchecked")
      ConstructorDef<Object>[] dummy = new ConstructorDef[0];
      parsed =
          new ClassNodeImpl<>(
              parent,
              n.getName(),
              n.getFullName(),
              cn.getIsUnit(),
              cn.getIsInjectionCandidate(),
              cn.getIsExternalConstructor(),
              injectableConstructors.toArray(dummy),
              allConstructors.toArray(dummy),
              cn.getDefaultImplementation());
    } else {
      throw new IllegalStateException("Bad protocol buffer: got abstract node" + n);
    }
    for (ClassHierarchyProto.Node child : n.getChildrenList()) {
      parseSubHierarchy(parsed, child);
    }
  }