Search in sources :

Example 1 with JsonSchema

use of com.fasterxml.jackson.module.jsonSchema.JsonSchema in project graylog2-server by Graylog2.

the class Generator method generateForRoute.

public Map<String, Object> generateForRoute(String route, String basePath) {
    Map<String, Object> result = Maps.newHashMap();
    Set<Class<?>> modelTypes = Sets.newHashSet();
    List<Map<String, Object>> apis = Lists.newArrayList();
    for (Class<?> clazz : getAnnotatedClasses()) {
        Path path = clazz.getAnnotation(Path.class);
        if (path == null) {
            LOG.debug("Skipping REST resource with no Api or Path annotation: <{}>", clazz.getCanonicalName());
            continue;
        }
        final String prefixedPath = prefixedPath(clazz, path.value());
        if (cleanRoute(route).equals(cleanRoute(prefixedPath))) {
            // This is the class representing the given route. Get all methods.
            LOG.debug("Found corresponding REST resource class: <{}>", clazz.getCanonicalName());
            Method[] methods = clazz.getDeclaredMethods();
            if (methods == null || methods.length == 0) {
                LOG.debug("REST resource <{}> has no methods. Skipping.", clazz.getCanonicalName());
                break;
            }
            for (Method method : methods) {
                if (!method.isAnnotationPresent(ApiOperation.class)) {
                    LOG.debug("Method <{}> has no ApiOperation annotation. Skipping.", method.toGenericString());
                    continue;
                }
                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
                Map<String, Object> api = Maps.newHashMap();
                List<Map<String, Object>> operations = Lists.newArrayList();
                String methodPath;
                if (method.isAnnotationPresent(Path.class)) {
                    // Method has annotated Path.
                    methodPath = cleanRoute(method.getAnnotation(Path.class).value());
                    if (clazz.isAnnotationPresent(Path.class)) {
                        // The class has a Path, too. Prepend.
                        String classPath = cleanRoute(prefixedPath(clazz, clazz.getAnnotation(Path.class).value()));
                        methodPath = classPath + methodPath;
                    }
                } else {
                    // Method has no annotated Path. We read from it's class.
                    if (clazz.isAnnotationPresent(Path.class)) {
                        methodPath = cleanRoute(prefixedPath(clazz, clazz.getAnnotation(Path.class).value()));
                    } else {
                        LOG.debug("Method <{}> has no Path annotation. Skipping.", method.toGenericString());
                        continue;
                    }
                }
                Produces produces = null;
                if (clazz.isAnnotationPresent(Produces.class) || method.isAnnotationPresent(Produces.class)) {
                    produces = clazz.getAnnotation(Produces.class);
                    if (method.isAnnotationPresent(Produces.class)) {
                        produces = method.getAnnotation(Produces.class);
                    }
                }
                api.put("path", methodPath);
                Map<String, Object> operation = Maps.newHashMap();
                operation.put("method", determineHttpMethod(method));
                operation.put("summary", apiOperation.value());
                operation.put("notes", apiOperation.notes());
                operation.put("nickname", method.getName());
                if (produces != null) {
                    operation.put("produces", produces.value());
                }
                // skip Response.class because we can't reliably infer any schema information from its payload anyway.
                if (!method.getReturnType().isAssignableFrom(Response.class)) {
                    operation.put("type", method.getReturnType().getSimpleName());
                    modelTypes.add(method.getReturnType());
                }
                List<Parameter> parameters = determineParameters(method);
                if (parameters != null && !parameters.isEmpty()) {
                    operation.put("parameters", parameters);
                }
                for (Parameter parameter : parameters) {
                    final Class type = parameter.getType();
                    if (Primitives.unwrap(type).isPrimitive() || type.equals(String.class)) {
                        continue;
                    }
                    modelTypes.add(type);
                }
                operation.put("responseMessages", determineResponses(method));
                operations.add(operation);
                api.put("operations", operations);
                apis.add(api);
            }
        }
    }
    if (basePath.endsWith("/")) {
        basePath = basePath.substring(0, basePath.length() - 1);
    }
    Collections.sort(apis, (o1, o2) -> ComparisonChain.start().compare(o1.get("path").toString(), o2.get("path").toString()).result());
    // generate the json schema for the auto-mapped return types
    Map<String, Object> models = Maps.newHashMap();
    for (Class<?> type : modelTypes) {
        // skip non-jackson mapped classes (like Response)
        if (!type.isAnnotationPresent(JsonAutoDetect.class)) {
            continue;
        }
        try {
            SchemaFactoryWrapper visitor = new SchemaFactoryWrapper();
            mapper.acceptJsonFormatVisitor(mapper.constructType(type), visitor);
            final JsonSchema schema = visitor.finalSchema();
            models.put(type.getSimpleName(), schema);
        } catch (JsonMappingException e) {
            LOG.error("Error generating model schema. Ignoring this model, this will likely break the API browser.", e);
        }
    }
    result.put("apis", apis);
    result.put("basePath", basePath);
    result.put("models", models);
    result.put("resourcePath", cleanRoute(route));
    result.put("apiVersion", ServerVersion.VERSION.toString());
    result.put("swaggerVersion", EMULATED_SWAGGER_VERSION);
    return result;
}
Also used : Path(javax.ws.rs.Path) JsonAutoDetect(com.fasterxml.jackson.annotation.JsonAutoDetect) JsonSchema(com.fasterxml.jackson.module.jsonSchema.JsonSchema) Method(java.lang.reflect.Method) Response(javax.ws.rs.core.Response) ApiResponse(io.swagger.annotations.ApiResponse) Produces(javax.ws.rs.Produces) JsonMappingException(com.fasterxml.jackson.databind.JsonMappingException) ApiOperation(io.swagger.annotations.ApiOperation) SchemaFactoryWrapper(com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper) Map(java.util.Map) ImmutableMap(com.google.common.collect.ImmutableMap)

Aggregations

JsonAutoDetect (com.fasterxml.jackson.annotation.JsonAutoDetect)1 JsonMappingException (com.fasterxml.jackson.databind.JsonMappingException)1 JsonSchema (com.fasterxml.jackson.module.jsonSchema.JsonSchema)1 SchemaFactoryWrapper (com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 ApiOperation (io.swagger.annotations.ApiOperation)1 ApiResponse (io.swagger.annotations.ApiResponse)1 Method (java.lang.reflect.Method)1 Map (java.util.Map)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 Response (javax.ws.rs.core.Response)1