All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.openapi.visitor.OpenApiControllerVisitor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017-2020 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.openapi.visitor;

import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.value.OptionalValues;
import io.micronaut.http.HttpMethod;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Consumes;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.HttpMethodMapping;
import io.micronaut.http.annotation.Produces;
import io.micronaut.http.annotation.UriMapping;
import io.micronaut.http.uri.UriMatchTemplate;
import io.micronaut.inject.ast.ClassElement;
import io.micronaut.inject.ast.MethodElement;
import io.micronaut.inject.visitor.TypeElementVisitor;
import io.micronaut.inject.visitor.VisitorContext;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.servers.Server;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

/**
 * A {@link TypeElementVisitor} the builds the Swagger model from Micronaut controllers at compile time.
 *
 * @author graemerocher
 * @since 1.0
 */
@Experimental
public class OpenApiControllerVisitor extends AbstractOpenApiEndpointVisitor implements TypeElementVisitor {

    @Override
    protected boolean ignore(ClassElement element, VisitorContext context) {
        return !element.isAnnotationPresent(Controller.class);
    }

    @Override
    protected boolean ignore(MethodElement element, VisitorContext context) {
        return element.isPrivate() || element.isStatic() || element.isAnnotationPresent(Hidden.class);
    }

    @Override
    protected HttpMethod httpMethod(MethodElement element) {
        Optional> httpMethodOpt = element
                .getAnnotationTypeByStereotype(HttpMethodMapping.class);
        if (!httpMethodOpt.isPresent()) {
            return null;
        }
        try {
            return HttpMethod.valueOf(httpMethodOpt.get().getSimpleName().toUpperCase(Locale.ENGLISH));
        } catch (IllegalArgumentException e) {
            // ignore
        }
        return null;
    }

    @Override
    protected List consumesMediaTypes(MethodElement element) {
        return mediaTypes(element, Consumes.class);
    }

    @Override
    protected List producesMediaTypes(MethodElement element) {
        return mediaTypes(element, Produces.class);
    }

    private List mediaTypes(MethodElement element, Class ann) {
        OptionalValues mts = element.getValues(ann, List.class);
        if (mts.isEmpty()) {
            return Collections.singletonList(MediaType.APPLICATION_JSON_TYPE);
        } else {
            List mediaTypes = new ArrayList<>();
            mts.forEach((key, list) ->
                list.stream().map(mt -> MediaType.of(mt.toString())).forEach(mt -> mediaTypes.add((MediaType) mt)));
            return mediaTypes;
        }
    }

    @Override
    protected List uriMatchTemplates(MethodElement element) {
        String controllerValue = element.getOwningType().getValue(UriMapping.class, String.class).orElse(element.getDeclaringType().getValue(UriMapping.class, String.class).orElse("/"));
        controllerValue = getPropertyPlaceholderResolver().resolvePlaceholders(controllerValue).orElse(controllerValue);
        UriMatchTemplate matchTemplate = UriMatchTemplate.of(controllerValue);
        // check if we have multiple uris
        String[] uris = element.stringValues(HttpMethodMapping.class, "uris");
        if (uris.length == 0) {
            String methodValue = element.getValue(HttpMethodMapping.class, String.class).orElse("/");
            methodValue = getPropertyPlaceholderResolver().resolvePlaceholders(methodValue).orElse(methodValue);
            return Collections.singletonList(matchTemplate.nest(methodValue));
        } else {
            List matchTemplates = new ArrayList<>(uris.length);
            for (String methodValue: uris) {
                methodValue = getPropertyPlaceholderResolver().resolvePlaceholders(methodValue).orElse(methodValue);
                matchTemplates.add(matchTemplate.nest(methodValue));
            }
            return matchTemplates;
        }
    }

    @Override
    protected String description(MethodElement element) {
        return null;
    }

    @Override
    protected List classTags(ClassElement element, VisitorContext context) {
        return Collections.emptyList();
    }

    @Override
    protected List methodServers(MethodElement element, VisitorContext context) {
        return processOpenApiAnnotation(
                element,
                context,
                io.swagger.v3.oas.annotations.servers.Server.class,
                io.swagger.v3.oas.models.servers.Server.class,
                Collections.emptyList()
        );
    }

    @Override
    protected List methodSecurityRequirements(MethodElement element, VisitorContext context) {
        return readSecurityRequirements(element);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy