001/* 002 * Copyright 2002-2020 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.server; 018 019import java.util.Collections; 020import java.util.Map; 021 022import org.springframework.core.NestedExceptionUtils; 023import org.springframework.core.NestedRuntimeException; 024import org.springframework.http.HttpHeaders; 025import org.springframework.http.HttpStatus; 026import org.springframework.lang.Nullable; 027import org.springframework.util.Assert; 028 029/** 030 * Base class for exceptions associated with specific HTTP response status codes. 031 * 032 * @author Rossen Stoyanchev 033 * @author Juergen Hoeller 034 * @since 5.0 035 */ 036@SuppressWarnings("serial") 037public class ResponseStatusException extends NestedRuntimeException { 038 039 private final HttpStatus status; 040 041 @Nullable 042 private final String reason; 043 044 045 /** 046 * Constructor with a response status. 047 * @param status the HTTP status (required) 048 */ 049 public ResponseStatusException(HttpStatus status) { 050 this(status, null, null); 051 } 052 053 /** 054 * Constructor with a response status and a reason to add to the exception 055 * message as explanation. 056 * @param status the HTTP status (required) 057 * @param reason the associated reason (optional) 058 */ 059 public ResponseStatusException(HttpStatus status, @Nullable String reason) { 060 this(status, reason, null); 061 } 062 063 /** 064 * Constructor with a response status and a reason to add to the exception 065 * message as explanation, as well as a nested exception. 066 * @param status the HTTP status (required) 067 * @param reason the associated reason (optional) 068 * @param cause a nested exception (optional) 069 */ 070 public ResponseStatusException(HttpStatus status, @Nullable String reason, @Nullable Throwable cause) { 071 super(null, cause); 072 Assert.notNull(status, "HttpStatus is required"); 073 this.status = status; 074 this.reason = reason; 075 } 076 077 078 /** 079 * Return the HTTP status associated with this exception. 080 */ 081 public HttpStatus getStatus() { 082 return this.status; 083 } 084 085 /** 086 * Return headers associated with the exception that should be added to the 087 * error response, e.g. "Allow", "Accept", etc. 088 * <p>The default implementation in this class returns an empty map. 089 * @since 5.1.11 090 * @deprecated as of 5.1.13 in favor of {@link #getResponseHeaders()} 091 */ 092 @Deprecated 093 public Map<String, String> getHeaders() { 094 return Collections.emptyMap(); 095 } 096 097 /** 098 * Return headers associated with the exception that should be added to the 099 * error response, e.g. "Allow", "Accept", etc. 100 * <p>The default implementation in this class returns empty headers. 101 * @since 5.1.13 102 */ 103 public HttpHeaders getResponseHeaders() { 104 Map<String, String> headers = getHeaders(); 105 if (headers.isEmpty()) { 106 return HttpHeaders.EMPTY; 107 } 108 HttpHeaders result = new HttpHeaders(); 109 getHeaders().forEach(result::add); 110 return result; 111 } 112 113 /** 114 * The reason explaining the exception (potentially {@code null} or empty). 115 */ 116 @Nullable 117 public String getReason() { 118 return this.reason; 119 } 120 121 122 @Override 123 public String getMessage() { 124 String msg = this.status + (this.reason != null ? " \"" + this.reason + "\"" : ""); 125 return NestedExceptionUtils.buildMessage(msg, getCause()); 126 } 127 128}