HandlerRegistry build() {
            // setDefaultExceptionHandler() must be called before invoking build()
            assert defaultExceptionHandler != null;

            // Store per-service first, to make sure services are added/replaced atomically.
            final ImmutableMap.Builder<String, ServerServiceDefinition> services = ImmutableMap.builder();
            final ImmutableMap.Builder<String, ServerMethodDefinition<?, ?>> methods = ImmutableMap.builder();
            final ImmutableMap.Builder<Route, ServerMethodDefinition<?, ?>> methodsByRoute =
                    ImmutableMap.builder();
            final ImmutableMap.Builder<MethodDescriptor<?, ?>, String> bareMethodNames = ImmutableMap.builder();
            final ImmutableMap.Builder<ServerMethodDefinition<?, ?>, List<DecoratorAndOrder>>
                    annotationDecorators = ImmutableMap.builder();
            final ImmutableMap.Builder<ServerMethodDefinition<?, ?>,
                    List<? extends Function<? super HttpService, ? extends HttpService>>>
                    additionalDecoratorsBuilder = ImmutableMap.builder();
            final ImmutableSet.Builder<ServerMethodDefinition<?, ?>> blockingMethods =
                    ImmutableSet.builder();
            final ImmutableMap.Builder<ServerMethodDefinition<?, ?>, GrpcExceptionHandlerFunction>
                    grpcExceptionHandlersBuilder = ImmutableMap.builder();
            final DependencyInjector dependencyInjector = new ReflectiveDependencyInjector();
            for (Entry entry : entries) {
                final ServerServiceDefinition service = entry.service();
                final String path = entry.path();
                services.put(path, service);
                final MethodDescriptor<?, ?> methodDescriptor = entry.method();
                final List<? extends Function<? super HttpService, ? extends HttpService>>
                        additionalDecorators = entry.additionalDecorators();
                if (methodDescriptor == null) {
                    final Class<?> type = entry.type();
                    final Map<String, Method> publicMethods = new HashMap<>();
                    if (type != null) {
                        for (Method method : InternalReflectionUtils.getAllSortedMethods(
                                type, withModifier(Modifier.PUBLIC))) {
                            final String methodName = method.getName();
                            if (!publicMethods.containsKey(methodName)) {
                                publicMethods.put(methodName, method);
                            }
                        }
                    }

                    for (ServerMethodDefinition<?, ?> methodDefinition : service.getMethods()) {
                        final MethodDescriptor<?, ?> methodDescriptor0 = methodDefinition.getMethodDescriptor();
                        final String bareMethodName = methodDescriptor0.getBareMethodName();
                        assert bareMethodName != null;
                        final String pathWithMethod = path + '/' + bareMethodName;
                        methods.put(pathWithMethod, methodDefinition);
                        methodsByRoute.put(Route.builder().exact('/' + pathWithMethod).build(),
                                           methodDefinition);
                        bareMethodNames.put(methodDescriptor0, bareMethodName);
                        if (!additionalDecorators.isEmpty()) {
                            additionalDecoratorsBuilder.put(methodDefinition, additionalDecorators);
                        }
                        final String methodName = methodNameConverter.convert(bareMethodName);
                        final Method method = publicMethods.get(methodName);
                        if (method != null) {
                            assert type != null;
                            final List<DecoratorAndOrder> decoratorAndOrders =
                                    DecoratorAnnotationUtil.collectDecorators(type, method);
                            if (!decoratorAndOrders.isEmpty()) {
                                annotationDecorators.put(methodDefinition, decoratorAndOrders);
                            }
                            if (needToUseBlockingTaskExecutor(type, method)) {
                                blockingMethods.add(methodDefinition);
                            }
                            putGrpcExceptionHandlerIfPresent(type, method, dependencyInjector,
                                                             methodDefinition, grpcExceptionHandlersBuilder,
                                                             defaultExceptionHandler);
                        }
                    }
                } else {
                    final ServerMethodDefinition<?, ?> methodDefinition =
                            service.getMethods().stream()
                                   .filter(method0 -> method0.getMethodDescriptor() == methodDescriptor)
                                   .findFirst()
                                   .orElseThrow(() -> new IllegalArgumentException(
                                           "Failed to retrieve " + methodDescriptor + " in " + service));
                    methods.put(path, methodDefinition);
                    additionalDecoratorsBuilder.put(methodDefinition, additionalDecorators);
                    methodsByRoute.put(Route.builder().exact('/' + path).build(), methodDefinition);
                    final MethodDescriptor<?, ?> methodDescriptor0 = methodDefinition.getMethodDescriptor();
                    final String bareMethodName = methodDescriptor0.getBareMethodName();
                    assert bareMethodName != null;
                    bareMethodNames.put(methodDescriptor0, bareMethodName);
                    final Class<?> type = entry.type();
                    if (type != null) {
                        final String methodName = methodNameConverter.convert(bareMethodName);
                        final Optional<Method> method =
                                InternalReflectionUtils.getAllSortedMethods(type, withModifier(Modifier.PUBLIC))
                                                       .stream()
                                                       .filter(m -> methodName.equals(m.getName()))
                                                       .findFirst();
                        if (method.isPresent()) {
                            final Method method0 = method.get();
                            final List<DecoratorAndOrder> decoratorAndOrders =
                                    DecoratorAnnotationUtil.collectDecorators(type, method0);
                            if (!decoratorAndOrders.isEmpty()) {
                                annotationDecorators.put(methodDefinition, decoratorAndOrders);
                            }
                            if (needToUseBlockingTaskExecutor(type, method0)) {
                                blockingMethods.add(methodDefinition);
                            }
                            putGrpcExceptionHandlerIfPresent(type, method0, dependencyInjector,
                                                             methodDefinition, grpcExceptionHandlersBuilder,
                                                             defaultExceptionHandler);
                        }
                    }
                }
            }
            final Map<String, ServerServiceDefinition> services0 = services.build();
            return new HandlerRegistry(ImmutableList.copyOf(services0.values()),
                                       methods.build(),
                                       methodsByRoute.build(),
                                       bareMethodNames.buildKeepingLast(),
                                       annotationDecorators.build(),
                                       additionalDecoratorsBuilder.build(),
                                       blockingMethods.build(),
                                       grpcExceptionHandlersBuilder.build(),
                                       defaultExceptionHandler);
        }
A registry of the implementation methods bound to a {@link GrpcService}. Used for method dispatch and
documentation generation.
grpc/src/main/java/com/linecorp/armeria/server/grpc/HandlerRegistry.java