@Override
  protected void exitBean(AbstractBean bean) {
    beans.pop();

    if (bean.getProperties().isEmpty() == false) {
      return;
    }
    if (bean.getNestedBeans().isEmpty() == false) {
      return;
    }

    // metadata was specifically requested for this bean
    if (bean.getElement().getAnnotation(Meta.class) != null) {
      return;
    }

    // remove this bean because its empty

    if (beans.isEmpty()) {
      // top level bean
      space.remove(bean.getElement());
    } else {
      // nested bean
      beans.peek().getNestedBeans().remove(bean.getElement());
    }
  }
  @Override
  public void resolveProperties(AbstractBean bean) {
    TypeElement type = bean.getElement();
    if (!ModelExt.hasAnyAnnotation(type, annots)) {
      return;
    }

    for (Element enclosed : type.getEnclosedElements()) {
      ElementExt ext = ModelExt.of(enclosed);
      if (ext.isProperty() && ext.getVisibility() != Visibility.PRIVATE) {
        String name = ext.getPropertyName();
        Property property = bean.getProperties().get(name);
        if (property == null) {
          property = new Property(name);
          bean.getProperties().put(name, property);
        }
        if (ext.isGetter()) {
          property.setGetter(enclosed);
        } else if (ext.isSetter()) {
          property.setSetter(enclosed);
        } else {
          property.setField(enclosed);
        }

        // jpa properties are always public
        property.setVisibility(Visibility.PUBLIC);
      }
    }
  }