Есть несколько серьёзных проблем:

1. Главная проблема: порядок выполнения

OASFilter выполняется во время сборки (build time), а ApiPlatformScanner с @Observes StartupEvent — во время запуска (runtime). Когда filterOperation() вызывается, ApiPlatformRegistry ещё пуст!

2. Массив CONTROLLERS пуст

private static final Class<?>[] CONTROLLERS = {
    // com.banank.platform.services.profile.controller.PersonController.class  // ← закомментировано!
};

3. Проблема с operationId

operationId в Quarkus обычно генерируется как read или PersonResource_read, а не содержит оба слова одновременно для проверки contains().


Решение: сканировать прямо в OASFilter

package com.banank.platform.services.profile.exception.utils;

import org.eclipse.microprofile.openapi.OASFactory;
import org.eclipse.microprofile.openapi.OASFilter;
import org.eclipse.microprofile.openapi.models.OpenAPI;
import org.eclipse.microprofile.openapi.models.Operation;
import org.eclipse.microprofile.openapi.models.PathItem;
import org.eclipse.microprofile.openapi.models.media.Content;
import org.eclipse.microprofile.openapi.models.responses.APIResponse;
import org.eclipse.microprofile.openapi.models.responses.APIResponses;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.MethodInfo;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PlatformApiOASFilter implements OASFilter {

    private static final DotName PLATFORM_API_RESPONSE = DotName.createSimple(PlatformApiResponse.class.getName());
    private static final DotName PLATFORM_API_RESPONSES = DotName.createSimple(PlatformApiResponses.class.getName());

    // Кэш: operationId -> List<AnnotationInstance>
    private final Map<String, List<AnnotationInstance>> responsesByOperation = new HashMap<>();

    public PlatformApiOASFilter() {
        loadAnnotationsFromJandex();
    }

    private void loadAnnotationsFromJandex() {
        try (InputStream stream = Thread.currentThread()
                .getContextClassLoader()
                .getResourceAsStream("META-INF/jandex.idx")) {
            
            if (stream == null) {
                System.err.println("Jandex index not found! Add quarkus-jandex dependency.");
                return;
            }

            Index index = new IndexReader(stream).read();

            // Ищем все @PlatformApiResponse
            for (AnnotationInstance annotation : index.getAnnotations(PLATFORM_API_RESPONSE)) {
                processAnnotation(annotation);
            }

            // Ищем все @PlatformApiResponses (контейнер)
            for (AnnotationInstance container : index.getAnnotations(PLATFORM_API_RESPONSES)) {
                AnnotationInstance[] values = container.value().asNestedArray();
                for (AnnotationInstance annotation : values) {
                    processAnnotation(annotation, container.target());
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void processAnnotation(AnnotationInstance annotation) {
        processAnnotation(annotation, annotation.target());
    }

    private void processAnnotation(AnnotationInstance annotation, org.jboss.jandex.AnnotationTarget target) {
        if (target.kind() == org.jboss.jandex.AnnotationTarget.Kind.METHOD) {
            MethodInfo method = target.asMethod();
            String className = method.declaringClass().simpleName();
            String methodName = method.name();
            
            // Возможные варианты operationId в Quarkus
            String key1 = methodName;                           // read
            String key2 = className + "_" + methodName;         // PersonResource_read
            
            responsesByOperation.computeIfAbsent(key1, k -> new ArrayList<>()).add(annotation);
            responsesByOperation.computeIfAbsent(key2, k -> new ArrayList<>()).add(annotation);
        }
    }

    @Override
    public Operation filterOperation(Operation operation) {
        if (operation == null || operation.getOperationId() == null) {
            return operation;
        }

        String operationId = operation.getOperationId();
        List<AnnotationInstance> annotations = responsesByOperation.get(operationId);

        if (annotations == null || annotations.isEmpty()) {
            return operation;
        }

        APIResponses responses = operation.getResponses();
        if (responses == null) {
            responses = OASFactory.createAPIResponses();
            operation.setResponses(responses);
        }

        for (AnnotationInstance annotation : annotations) {
            String responseCode = annotation.value("responseCode") != null 
                    ? annotation.value("responseCode").asString() 
                    : "default";
            String description = annotation.value("description") != null 
                    ? annotation.value("description").asString() 
                    : "";

            // Не перезаписываем существующие responses
            if (responses.getAPIResponse(responseCode) != null) {
                continue;
            }

            APIResponse apiResponse = OASFactory.createAPIResponse()
                    .description(description);

            // Обработка content если есть
            if (annotation.value("content") != null) {
                AnnotationInstance[] contents = annotation.value("content").asNestedArray();
                if (contents.length > 0) {
                    Content content = OASFactory.createContent();
                    for (AnnotationInstance c : contents) {
                        String mediaType = c.value("mediaType") != null 
                                ? c.value("mediaType").asString() 
                                : "application/json";
                        content.addMediaType(mediaType, OASFactory.createMediaType());
                    }
                    apiResponse.setContent(content);
                }
            }

            responses.addAPIResponse(responseCode, apiResponse);
        }

        return operation;
    }
}

Необходимые изменения:

1. Добавить зависимость Jandex (если нет):

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-jandex</artifactId>
</dependency>

2. Зарегистрировать фильтр в application.properties:

mp.openapi.filter=com.banank.platform.services.profile.exception.utils.PlatformApiOASFilter

3. Убедиться что класс индексируется:

quarkus.index-dependency.your-module.group-id=com.banank
quarkus.index-dependency.your-module.artifact-id=your-artifact

Альтернатива: упрощённый вариант без Jandex

Если не хотите возиться с Jandex, можно сделать статическую регистрацию в static блоке:

public class PlatformApiOASFilter implements OASFilter {

    private static final Map<String, List<ResponseInfo>> RESPONSES = new HashMap<>();

    static {
        // Регистрируем вручную или через рефлексию в static блоке
        registerFromClass(PersonResource.class);
    }

    private static void registerFromClass(Class<?> clazz) {
        for (var method : clazz.getDeclaredMethods()) {
            List<PlatformApiResponse> annotations = new ArrayList<>();
            
            PlatformApiResponses container = method.getAnnotation(PlatformApiResponses.class);
            if (container != null) {
                annotations.addAll(Arrays.asList(container.value()));
            }
            
            PlatformApiResponse single = method.getAnnotation(PlatformApiResponse.class);
            if (single != null) {
                annotations.add(single);
            }
            
            if (!annotations.isEmpty()) {
                String key = method.getName(); // или clazz.getSimpleName() + "_" + method.getName()
                RESPONSES.put(key, annotations.stream()
                        .map(a -> new ResponseInfo(a.responseCode(), a.description()))
                        .toList());
            }
        }
    }

    record ResponseInfo(String code, String description) {}

    @Override
    public Operation filterOperation(Operation operation) {
        // ... использовать RESPONSES map
    }
}

Но это требует явно перечислять классы контроллеров.