class AmbariSwaggerReader extends JaxrsReader {

  @Override
  public Swagger read(Set<Class<?>> classes) {
    // scan for and register nested API classes
    logger.debug("Looking for nested API's");
    for (Class<?> cls: classes) {
      logger.debug("Examining API {}", cls.getSimpleName());
      for (Method method: cls.getMethods()) {
        Path methodPath = AnnotationUtils.findAnnotation(method, Path.class);
        if (null != methodPath) {
          Class<?> returnType = method.getReturnType();
          Api nestedApi = AnnotationUtils.findAnnotation(returnType, Api.class);
          Path nestedApiPath = AnnotationUtils.findAnnotation(returnType, Path.class);
          logger.debug("Examining API method {}#{}, path={}, returnType={}", cls.getSimpleName(), method.getName(),
              nestedApiPath != null ? nestedApiPath.value() : null, returnType.getSimpleName());
          if (null != nestedApi) {
            if (null != nestedApiPath) {
              logger.info("This class exists both as top level and nested API: {}, treating it as top level API",
                  returnType.getName());
            }
            else {
              boolean skipAdd = false;
              Class<?> preferredParentClass = cls;
              String parentApiPath;
              String methodPathAsString = methodPath.value();

              // API is a nested API of multiple top level APIs
              if (nestedAPIs.containsKey(returnType)) {
                SwaggerPreferredParent preferredParentAnnotation = AnnotationUtils.findAnnotation(returnType,
                        SwaggerPreferredParent.class);
                if (null != preferredParentAnnotation) {
                  preferredParentClass = preferredParentAnnotation.preferredParent();
                  if (nestedAPIs.get(returnType).parentApi.getName().equals(preferredParentClass.getName())) {
                    skipAdd = true;
                  } else {
                    logger.info("Setting top level API of {} to {} based on @SwaggerPreferredParent " +
                            "annotation", returnType, preferredParentClass.getSimpleName());
                    try {
                      method = preferredParentClass.getMethod(method.getName(), method.getParameterTypes());
                    } catch (NoSuchMethodException exc) {
                      skipAdd = true;
                      logger.error("{} class defined as parent API is invalid due to method mismatch! Ignoring " +
                              "API {}", preferredParentClass, returnType);
                    }
                  }
                } else {
                  logger.warn("{} is a nested API of multiple top level API's. Ignoring top level API {}",
                          returnType, cls);
                  skipAdd = true;
                }
              }

              if (skipAdd) {
                continue;
              } else {
                nestedAPIs.remove(returnType);
              }

              // API parent customization by @SwaggerOverwriteNestedAPI
              SwaggerOverwriteNestedAPI swaggerOverwriteNestedAPI = AnnotationUtils.findAnnotation(returnType,
                      SwaggerOverwriteNestedAPI.class);
              if (null != swaggerOverwriteNestedAPI) {
                preferredParentClass = swaggerOverwriteNestedAPI.parentApi();
                parentApiPath = swaggerOverwriteNestedAPI.parentApiPath();
                methodPathAsString = swaggerOverwriteNestedAPI.parentMethodPath();
              } else {
                parentApiPath = validateParentApiPath(preferredParentClass);
              }

              logger.info("Registering nested API: {}", returnType);
              NestedApiRecord nar = new NestedApiRecord(returnType, preferredParentClass, parentApiPath, method,
                methodPathAsString);
              nestedAPIs.put(returnType, nar);
            }
          }
        }
      }
    }
    logger.info("Found {} nested API's", nestedAPIs.size());
    // With all information gathered, call superclass implementation
    return super.read(classes);
  }

  public  AmbariSwaggerReader(Swagger swagger, Log LOG);

}