@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(
     MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
   returnType.increaseNestingLevel();
   Type nestedType = returnType.getNestedGenericParameterType();
   returnType.decreaseNestingLevel();
   return ResourceSupport.class.isAssignableFrom(returnType.getParameterType())
       || TypeUtils.isAssignable(ResourceSupport.class, nestedType);
 }
  @Override
  public Mono<Object> resolveArgument(
      MethodParameter param, BindingContext bindingContext, ServerWebExchange exchange) {

    ResolvableType entityType = ResolvableType.forMethodParameter(param);
    MethodParameter bodyParameter = new MethodParameter(param);
    bodyParameter.increaseNestingLevel();

    return readBody(bodyParameter, false, bindingContext, exchange)
        .map(body -> createHttpEntity(body, entityType, exchange))
        .defaultIfEmpty(createHttpEntity(null, entityType, exchange));
  }
 private synchronized void setExclusiveTargetParameterType(
     TypeDescriptor targetParameterType, MethodParameter methodParameter) {
   if (this.targetParameterTypeDescriptor != null) {
     throw new IneligibleMethodException(
         "Found more than one parameter type candidate: ["
             + this.targetParameterTypeDescriptor
             + "] and ["
             + targetParameterType
             + "]");
   }
   this.targetParameterTypeDescriptor = targetParameterType;
   if (Message.class.isAssignableFrom(targetParameterType.getObjectType())) {
     methodParameter.increaseNestingLevel();
     this.targetParameterType = methodParameter.getNestedParameterType();
     methodParameter.decreaseNestingLevel();
   } else {
     this.targetParameterType = targetParameterType.getObjectType();
   }
 }
  @SuppressWarnings("unchecked")
  protected Map convertToTypedMap(
      Map original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {

    boolean originalAllowed = requiredType.isInstance(original);
    if (!originalAllowed && !Map.class.isAssignableFrom(requiredType)) {
      return original;
    }

    Class keyType = null;
    Class valueType = null;
    MethodParameter methodParam = typeDescriptor.getMethodParameter();
    if (methodParam != null) {
      keyType = GenericCollectionTypeResolver.getMapKeyParameterType(methodParam);
      valueType = GenericCollectionTypeResolver.getMapValueParameterType(methodParam);
    }
    if (keyType == null
        && valueType == null
        && originalAllowed
        && !this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
      return original;
    }

    Iterator it;
    try {
      it = original.entrySet().iterator();
      if (it == null) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Map of type ["
                  + original.getClass().getName()
                  + "] returned null Iterator - injecting original Map as-is");
        }
        return original;
      }
    } catch (Throwable ex) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Cannot access Map of type ["
                + original.getClass().getName()
                + "] - injecting original Map as-is",
            ex);
      }
      return original;
    }

    Map convertedCopy;
    try {
      if (CollectionFactory.isApproximableMapType(requiredType)) {
        convertedCopy = CollectionFactory.createApproximateMap(original, original.size());
      } else {
        convertedCopy = (Map) requiredType.newInstance();
      }
    } catch (Throwable ex) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Cannot create copy of Map type ["
                + original.getClass().getName()
                + "] - injecting original Map as-is",
            ex);
      }
      return original;
    }

    while (it.hasNext()) {
      Map.Entry entry = (Map.Entry) it.next();
      Object key = entry.getKey();
      Object value = entry.getValue();
      String keyedPropertyName = buildKeyedPropertyName(propertyName, key);
      if (methodParam != null) {
        methodParam.increaseNestingLevel();
        methodParam.setTypeIndexForCurrentLevel(0);
      }
      Object convertedKey =
          convertIfNecessary(keyedPropertyName, null, key, keyType, typeDescriptor);
      if (methodParam != null) {
        methodParam.setTypeIndexForCurrentLevel(1);
      }
      Object convertedValue =
          convertIfNecessary(keyedPropertyName, null, value, valueType, typeDescriptor);
      if (methodParam != null) {
        methodParam.decreaseNestingLevel();
      }
      try {
        convertedCopy.put(convertedKey, convertedValue);
      } catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Map type ["
                  + original.getClass().getName()
                  + "] seems to be read-only - injecting original Map as-is",
              ex);
        }
        return original;
      }
      originalAllowed = originalAllowed && (key == convertedKey) && (value == convertedValue);
    }
    return (originalAllowed ? original : convertedCopy);
  }
  @SuppressWarnings("unchecked")
  protected Collection convertToTypedCollection(
      Collection original, String propertyName, Class requiredType, TypeDescriptor typeDescriptor) {

    boolean originalAllowed = requiredType.isInstance(original);
    if (!originalAllowed && !Collection.class.isAssignableFrom(requiredType)) {
      return original;
    }

    MethodParameter methodParam = typeDescriptor.getMethodParameter();
    Class elementType = null;
    if (methodParam != null) {
      elementType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
    }
    if (elementType == null
        && originalAllowed
        && !this.propertyEditorRegistry.hasCustomEditorForElement(null, propertyName)) {
      return original;
    }

    Iterator it;
    try {
      it = original.iterator();
      if (it == null) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Collection of type ["
                  + original.getClass().getName()
                  + "] returned null Iterator - injecting original Collection as-is");
        }
        return original;
      }
    } catch (Throwable ex) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Cannot access Collection of type ["
                + original.getClass().getName()
                + "] - injecting original Collection as-is",
            ex);
      }
      return original;
    }

    Collection convertedCopy;
    try {
      if (CollectionFactory.isApproximableCollectionType(requiredType)) {
        convertedCopy = CollectionFactory.createApproximateCollection(original, original.size());
      } else {
        convertedCopy = (Collection) requiredType.newInstance();
      }
    } catch (Throwable ex) {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Cannot create copy of Collection type ["
                + original.getClass().getName()
                + "] - injecting original Collection as-is",
            ex);
      }
      return original;
    }

    int i = 0;
    for (; it.hasNext(); i++) {
      Object element = it.next();
      String indexedPropertyName = buildIndexedPropertyName(propertyName, i);
      if (methodParam != null) {
        methodParam.increaseNestingLevel();
      }
      Object convertedElement =
          convertIfNecessary(indexedPropertyName, null, element, elementType, typeDescriptor);
      if (methodParam != null) {
        methodParam.decreaseNestingLevel();
      }
      try {
        convertedCopy.add(convertedElement);
      } catch (Throwable ex) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "Collection type ["
                  + original.getClass().getName()
                  + "] seems to be read-only - injecting original Collection as-is",
              ex);
        }
        return original;
      }
      originalAllowed = originalAllowed && (element == convertedElement);
    }
    return (originalAllowed ? original : convertedCopy);
  }