private Operation buildOperation()

in geronimo-openapi-impl/src/main/java/org/apache/geronimo/microprofile/openapi/impl/processor/AnnotationProcessor.java [246:449]


    private Operation buildOperation(final OpenAPI api, final AnnotatedMethodElement m, final AnnotatedElement declaring,
                                     final String httpVerb, final String path) {
        final Optional<org.eclipse.microprofile.openapi.annotations.Operation> opOpt = ofNullable(m.getAnnotation(org.eclipse.microprofile.openapi.annotations.Operation.class));
        if (opOpt.map(org.eclipse.microprofile.openapi.annotations.Operation::hidden).orElse(false)) {
            return null;
        }

        final Optional<List<String>> produces = findProduces(m);

        final OperationImpl operation = new OperationImpl();

        if (opOpt.isPresent()) {
            final org.eclipse.microprofile.openapi.annotations.Operation op = opOpt.get();
            if (!op.operationId().isEmpty()) {
                operation.operationId(op.operationId());
            } else {
                operation.operationId(createOperationId(m, httpVerb, path));
            }
            if (!op.summary().isEmpty()) {
                operation.summary(op.summary());
            }
            operation.deprecated(op.deprecated());
            if (!op.description().isEmpty()) {
                operation.description(op.description());
            }
        } else {
            operation.operationId(createOperationId(m, httpVerb, path));
        }

        final Optional<String> servers = ofNullable(config.read(OASConfig.SERVERS_OPERATION_PREFIX + operation.getOperationId(), null));
        if (servers.isPresent()) {
            servers.ifPresent(s -> operation.servers(mapConfiguredServers(s)));
        } else {
            ofNullable(ofNullable(findServers(m)).orElseGet(() -> findServers(declaring)))
                    .ifPresent(it -> operation.servers(Stream.of(it).map(this::mapServer).collect(toList())));
        }

        of(m.getAnnotationsByType(Callback.class)).filter(it -> it.length > 0).ifPresent(cbs -> {
            final Map<String, org.eclipse.microprofile.openapi.models.callbacks.Callback> callbacks = Stream.of(cbs)
                    .collect(toMap(it -> of(it.name()).filter(n -> !n.isEmpty()).orElseGet(() -> it.ref()),
                            it -> mapCallback(api, it)));
            operation.callbacks(callbacks);
        });

        ofNullable(m.getAnnotation(SecurityScheme.class))
                .ifPresent(s -> {
                    org.eclipse.microprofile.openapi.models.Components components = api.getComponents();
                    if (components == null) {
                        components = new ComponentsImpl();
                        api.setComponents(components);
                    }
                    components.addSecurityScheme(s.ref(), mapSecurityScheme(s));
                });

        ofNullable(m.getAnnotationsByType(Extension.class))
                .map(this::mapExtensions)
                .ifPresent(exts -> exts.forEach(operation::addExtension));

        operation.security(of(Stream.concat(
                Stream.of(m.getAnnotationsByType(SecurityRequirement.class)),
                Stream.of(m.getDeclaringClass().getAnnotationsByType(SecurityRequirement.class)))
                .map(this::mapSecurity).collect(toList()))
                .filter(s -> !s.isEmpty())
                .orElse(null));

        ofNullable(findTags(m, declaring))
                .map(tags -> Stream.of(tags)
                     .map(it -> of(it.name())
                            .filter(v -> !v.isEmpty())
                            .map(tag -> {
                                api.addTag(mapTag(it));
                                return tag;
                            }).filter(v -> !v.isEmpty())
                            .orElseGet(() -> {
                                final String ref = it.ref();
                                return Stream.of(declaring.getAnnotationsByType(Tag.class))
                                    .filter(t -> t.name().equals(ref))
                                    .findFirst()
                                    .map(Tag::name)
                                    .filter(v -> !v.isEmpty())
                                    .orElseGet(() -> api.getTags().stream()
                                        .filter(t -> t.getName().equals(ref))
                                        .findFirst()
                                        .map(org.eclipse.microprofile.openapi.models.tags.Tag::getName)
                                        .orElse(ref));
                           }))
                     .distinct()
                     .filter(v -> !v.isEmpty())
                     .collect(toList()))
                .ifPresent(operation::tags);

        of(m.getAnnotationsByType(APIResponse.class)).filter(s -> s.length > 0).ifPresent(items -> {
            final APIResponses responses = new APIResponsesImpl();
            responses.putAll(Stream.of(items).collect(toMap(it -> of(it.responseCode()).filter(c -> !c.isEmpty()).orElse("200"),
                    it -> mapResponse(() -> getOrCreateComponents(api), it, produces.orElse(null)), (a, b) -> b)));
            responses.values().stream()
                     .filter(it -> it.getContent() == null || it.getContent().isEmpty() ||
                             it.getContent().values().stream().anyMatch(c -> c.getSchema() == null))
                     .forEach(v -> {
                         Type returnType = m.getReturnType();
                         if (returnType == void.class || returnType == Response.class) {
                             if (v.getContent() == null || v.getContent().isEmpty()) {
                                 final ContentImpl content = new ContentImpl();

                                 produces
                                     .orElseGet(() -> singletonList("*/*"))
                                     .forEach(mt -> content.addMediaType(mt, new MediaTypeImpl()));
                                 
                                 v.content(content);
                             }
                             return;
                         }

                         if (ParameterizedType.class.isInstance(returnType)) {
                             final ParameterizedType pt = ParameterizedType.class.cast(returnType);
                             if (pt.getActualTypeArguments().length > 0) {
                                 if (pt.getRawType() == CompletionStage.class) {
                                     returnType = pt.getActualTypeArguments()[0];
                                 }
                             }
                         }
                         final org.eclipse.microprofile.openapi.models.media.Schema schema =
                                 schemaProcessor.mapSchemaFromClass(
                                         () -> getOrCreateComponents(api), returnType);
                         if (v.getContent() == null || v.getContent().isEmpty()) {
                             final ContentImpl content = new ContentImpl();
                             final MediaTypeImpl mediaType = new MediaTypeImpl();
                             mediaType.setSchema(schema);
                             content.addMediaType("", mediaType);
                             v.content(content);
                         } else {
                             v.getContent().values().stream()
                                .filter(it -> it.getSchema() == null)
                                .forEach(it -> it.schema(schema));
                         }
                    });
            responses.values().stream().filter(r -> r.getContent() != null)
                     .forEach(resp -> ofNullable(resp.getContent().remove(""))
                             .ifPresent(updated -> produces.ifPresent(mt -> mt.forEach(type -> resp.getContent().addMediaType(type, updated)))));
            operation.responses(responses);
        });
        operation.parameters(Stream.of(m.getParameters())
                .filter(it -> it.isAnnotationPresent(Parameter.class) || hasJaxRsParams(it))
                .flatMap(it -> buildParameter(it, api)
                        .orElseGet(() -> {
                            final ParameterImpl parameter = new ParameterImpl();
                            parameter.schema(schemaProcessor.mapSchemaFromClass(
                                    () -> getOrCreateComponents(api), it.getType()));
                            return Stream.of(parameter);
                        }))
                .filter(Objects::nonNull).collect(toList()));
        Stream.of(m.getParameters())
                .filter(it -> it.isAnnotationPresent(Parameters.class))
                .map(it -> it.getAnnotation(Parameters.class).value())
                .forEach(params -> operation.parameters(mapParameters(api, params)));
        Stream.of(m.getParameters())
                .filter(p -> p.isAnnotationPresent(RequestBody.class) ||
                        (!p.isAnnotationPresent(Suspended.class) && !p.isAnnotationPresent(Context.class) &&
                                !p.isAnnotationPresent(Parameter.class) && !hasJaxRsParams(p)))
                .findFirst()
                .ifPresent(p -> operation.requestBody(mapRequestBody(
                        produces.filter(it -> !it.isEmpty()).map(it -> it.iterator().next()).orElse(null), p,
                        () -> getOrCreateComponents(api), ofNullable(p.getAnnotation(RequestBody.class))
                    .orElseGet(() -> m.getAnnotation(RequestBody.class)))));
        // ensure parameters have all schemas
        operation.getParameters().stream()
                .filter(it -> it.getSchema() == null)
                .forEach(it -> Stream.of(m.getParameters())
                        .filter(mp -> findAnnotatedParameterByName(it, mp))
                        .findFirst()
                        .ifPresent(mp -> it.setSchema(schemaProcessor.mapSchemaFromClass(() -> getOrCreateComponents(api), mp.getType()))));
        // ensure parameter contents have all schemas
        operation.getParameters().stream()
                .filter(it -> it.getContent() != null && it.getContent().values().stream().anyMatch(c -> c.getSchema() == null || c.getSchema().getType() == null))
                .forEach(it -> Stream.of(m.getParameters())
                        .filter(mp -> findAnnotatedParameterByName(it, mp))
                        .findFirst()
                        .ifPresent(mp -> it.getContent().values().stream().filter(c -> c.getSchema() == null || c.getSchema().getType() == null).forEach(mt -> {
                            final org.eclipse.microprofile.openapi.models.media.Schema schema = schemaProcessor.mapSchemaFromClass(() -> getOrCreateComponents(api), mp.getType());
                            if (mt.getSchema() == null) {
                                mt.setSchema(schema);
                            } else {
                                mt.getSchema().type(schema.getType());
                            }
                        })));
        if (operation.getResponses() == null) {
            final APIResponsesImpl responses = new APIResponsesImpl();
            operation.responses(responses);
            final boolean normalResponse = Stream.of(m.getParameters()).noneMatch(it -> it.isAnnotationPresent(Suspended.class));
            final ContentImpl content = new ContentImpl();
            if (normalResponse) {
                final MediaType impl = new MediaTypeImpl();
                impl.setSchema(schemaProcessor.mapSchemaFromClass(() -> getOrCreateComponents(api), m.getReturnType()));
                produces.orElseGet(() -> singletonList("*/*")).forEach(key -> content.addMediaType(key, impl));
            }
            final org.eclipse.microprofile.openapi.models.responses.APIResponse defaultResponse =
                    new APIResponseImpl().description("default response").content(content);
            responses.addApiResponse(
                    m.getReturnType() == void.class || m.getReturnType() == Void.class && normalResponse ?
                            "204" : "200", defaultResponse);
            responses.defaultValue(defaultResponse);
        }
        return operation;
    }