Support "Accept-Patch" for unsupported media type

This commit introduces support in both servlet and webflux for the
"Accept-Patch" header, which is sent when the client sends unsupported
data in PATCH requests.
See  section 2.2 of RFC 5789.

Closes gh-26759
This commit is contained in:
Arjen Poutsma
2021-04-08 14:26:24 +02:00
parent 97f3846971
commit a2d91a562d
8 changed files with 117 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,12 @@ import java.util.Collections;
import java.util.List;
import org.springframework.core.ResolvableType;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
/**
* Exception for errors that fit response status 415 (unsupported media type).
@@ -41,6 +44,9 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
@Nullable
private final ResolvableType bodyType;
@Nullable
private final HttpMethod method;
/**
* Constructor for when the specified Content-Type is invalid.
@@ -50,13 +56,14 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
this.contentType = null;
this.supportedMediaTypes = Collections.emptyList();
this.bodyType = null;
this.method = null;
}
/**
* Constructor for when the Content-Type can be parsed but is not supported.
*/
public UnsupportedMediaTypeStatusException(@Nullable MediaType contentType, List<MediaType> supportedTypes) {
this(contentType, supportedTypes, null);
this(contentType, supportedTypes, null, null);
}
/**
@@ -65,11 +72,30 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
*/
public UnsupportedMediaTypeStatusException(@Nullable MediaType contentType, List<MediaType> supportedTypes,
@Nullable ResolvableType bodyType) {
this(contentType, supportedTypes, bodyType, null);
}
/**
* Constructor that provides the HTTP method.
* @since 5.3.6
*/
public UnsupportedMediaTypeStatusException(@Nullable MediaType contentType, List<MediaType> supportedTypes,
@Nullable HttpMethod method) {
this(contentType, supportedTypes, null, method);
}
/**
* Constructor for when trying to encode from or decode to a specific Java type.
* @since 5.3.6
*/
public UnsupportedMediaTypeStatusException(@Nullable MediaType contentType, List<MediaType> supportedTypes,
@Nullable ResolvableType bodyType, @Nullable HttpMethod method) {
super(HttpStatus.UNSUPPORTED_MEDIA_TYPE, initReason(contentType, bodyType));
this.contentType = contentType;
this.supportedMediaTypes = Collections.unmodifiableList(supportedTypes);
this.bodyType = bodyType;
this.method = method;
}
private static String initReason(@Nullable MediaType contentType, @Nullable ResolvableType bodyType) {
@@ -107,4 +133,14 @@ public class UnsupportedMediaTypeStatusException extends ResponseStatusException
return this.bodyType;
}
@Override
public HttpHeaders getResponseHeaders() {
if (HttpMethod.PATCH != this.method || CollectionUtils.isEmpty(this.supportedMediaTypes) ) {
return HttpHeaders.EMPTY;
}
HttpHeaders headers = new HttpHeaders();
headers.setAcceptPatch(this.supportedMediaTypes);
return headers;
}
}