/**
   * Invokes all {@link ResourceProcessor} instances registered for the type of the given value and
   * reference type.
   *
   * @param value must not be {@literal null}.
   * @param referenceType must not be {@literal null}.
   * @return
   */
  @SuppressWarnings("unchecked")
  public <T extends ResourceSupport> T invokeProcessorsFor(T value, ResolvableType referenceType) {

    Assert.notNull(value, "Value must not be null!");
    Assert.notNull(referenceType, "Reference type must not be null!");

    // For Resources implementations, process elements first
    if (ResourceProcessorHandlerMethodReturnValueHandler.RESOURCES_TYPE.isAssignableFrom(
        referenceType)) {

      Resources<?> resources = (Resources<?>) value;
      ResolvableType elementTargetType =
          ResolvableType.forClass(Resources.class, referenceType.getRawClass()).getGeneric(0);
      List<Object> result = new ArrayList<Object>(resources.getContent().size());

      for (Object element : resources) {

        ResolvableType elementType = ResolvableType.forClass(element.getClass());

        if (!getRawType(elementTargetType).equals(elementType.getRawClass())) {
          elementTargetType = elementType;
        }

        result.add(invokeProcessorsFor(element, elementTargetType));
      }

      ReflectionUtils.setField(
          ResourceProcessorHandlerMethodReturnValueHandler.CONTENT_FIELD, resources, result);
    }

    return (T) invokeProcessorsFor((Object) value, referenceType);
  }
 @Override
 public boolean supportsEventType(ResolvableType resolvableType) {
   Class<?> type = resolvableType.getRawClass();
   if (type == null) {
     return false;
   }
   return ApplicationStartedEvent.class.isAssignableFrom(type)
       || ApplicationFailedEvent.class.isAssignableFrom(type);
 }
  private Object createHttpEntity(
      Object body, ResolvableType entityType, ServerWebExchange exchange) {

    ServerHttpRequest request = exchange.getRequest();
    HttpHeaders headers = request.getHeaders();
    if (RequestEntity.class == entityType.getRawClass()) {
      return new RequestEntity<>(body, headers, request.getMethod(), request.getURI());
    } else {
      return new HttpEntity<>(body, headers);
    }
  }
 private ResolvableType getResolvableType(ApplicationEvent event) {
   ResolvableType payloadType = null;
   if (event instanceof PayloadApplicationEvent) {
     PayloadApplicationEvent<?> payloadEvent = (PayloadApplicationEvent<?>) event;
     payloadType =
         payloadEvent.getResolvableType().as(PayloadApplicationEvent.class).getGeneric(0);
   }
   for (ResolvableType declaredEventType : this.declaredEventTypes) {
     if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass())
         && payloadType != null) {
       if (declaredEventType.isAssignableFrom(payloadType)) {
         return declaredEventType;
       }
     }
     if (declaredEventType.getRawClass().isAssignableFrom(event.getClass())) {
       return declaredEventType;
     }
   }
   return null;
 }
 @Override
 public boolean supportsEventType(ResolvableType eventType) {
   for (ResolvableType declaredEventType : this.declaredEventTypes) {
     if (declaredEventType.isAssignableFrom(eventType)) {
       return true;
     } else if (PayloadApplicationEvent.class.isAssignableFrom(eventType.getRawClass())) {
       ResolvableType payloadType = eventType.as(PayloadApplicationEvent.class).getGeneric();
       if (declaredEventType.isAssignableFrom(payloadType)) {
         return true;
       }
     }
   }
   return eventType.hasUnresolvableGenerics();
 }
 /**
  * Resolve the method arguments to use for the specified {@link ApplicationEvent}.
  *
  * <p>These arguments will be used to invoke the method handled by this instance. Can return
  * {@code null} to indicate that no suitable arguments could be resolved and therefore the method
  * should not be invoked at all for the specified event.
  */
 protected Object[] resolveArguments(ApplicationEvent event) {
   ResolvableType declaredEventType = getResolvableType(event);
   if (declaredEventType == null) {
     return null;
   }
   if (this.method.getParameterCount() == 0) {
     return new Object[0];
   }
   if (!ApplicationEvent.class.isAssignableFrom(declaredEventType.getRawClass())
       && event instanceof PayloadApplicationEvent) {
     return new Object[] {((PayloadApplicationEvent) event).getPayload()};
   } else {
     return new Object[] {event};
   }
 }
  @Override
  public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {

    ResolvableType returnType = result.getReturnType();
    MethodParameter bodyType;

    Mono<?> returnValueMono;
    Optional<Object> optionalValue = result.getReturnValue();

    Class<?> rawClass = returnType.getRawClass();
    ReactiveAdapter adapter = getAdapterRegistry().getAdapterFrom(rawClass, optionalValue);

    if (adapter != null) {
      returnValueMono = adapter.toMono(optionalValue);
      bodyType = new MethodParameter(result.getReturnTypeSource());
      bodyType.increaseNestingLevel();
      bodyType.increaseNestingLevel();
    } else {
      returnValueMono = Mono.justOrEmpty(optionalValue);
      bodyType = new MethodParameter(result.getReturnTypeSource());
      bodyType.increaseNestingLevel();
    }

    return returnValueMono.then(
        returnValue -> {
          Assert.isInstanceOf(HttpEntity.class, returnValue);
          HttpEntity<?> httpEntity = (HttpEntity<?>) returnValue;

          if (httpEntity instanceof ResponseEntity) {
            ResponseEntity<?> responseEntity = (ResponseEntity<?>) httpEntity;
            exchange.getResponse().setStatusCode(responseEntity.getStatusCode());
          }

          HttpHeaders entityHeaders = httpEntity.getHeaders();
          HttpHeaders responseHeaders = exchange.getResponse().getHeaders();

          if (!entityHeaders.isEmpty()) {
            entityHeaders
                .entrySet()
                .stream()
                .filter(entry -> !responseHeaders.containsKey(entry.getKey()))
                .forEach(entry -> responseHeaders.put(entry.getKey(), entry.getValue()));
          }

          return writeBody(httpEntity.getBody(), bodyType, exchange);
        });
  }
  @Override
  public boolean supports(HandlerResult result) {
    Class<?> returnType = result.getReturnType().getRawClass();
    if (isSupportedType(returnType)) {
      return true;
    } else {
      ReactiveAdapter adapter =
          getAdapterRegistry().getAdapterFrom(returnType, result.getReturnValue());
      if (adapter != null
          && !adapter.getDescriptor().isMultiValue()
          && !adapter.getDescriptor().isNoValue()) {

        ResolvableType genericType = result.getReturnType().getGeneric(0);
        return isSupportedType(genericType.getRawClass());
      }
    }
    return false;
  }
  private static Class<?> getRawType(ResolvableType type) {

    Class<?> rawType = type.getRawClass();
    return rawType == null ? Object.class : rawType;
  }
 @Override
 public boolean canEncode(ResolvableType elementType, MimeType mimeType, Object... hints) {
   Class<?> clazz = elementType.getRawClass();
   return (super.canEncode(elementType, mimeType, hints)
       && Resource.class.isAssignableFrom(clazz));
 }