11/*
2- * Copyright 2002-2024 the original author or authors.
2+ * Copyright 2002-2025 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
@@ -97,7 +97,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
9797
9898 private final ByteArrayOutputStream content = new ByteArrayOutputStream (1024 );
9999
100- private final ServletOutputStream outputStream = new ResponseServletOutputStream ( this . content ) ;
100+ private @ Nullable ServletOutputStream outputStream ;
101101
102102 private @ Nullable PrintWriter writer ;
103103
@@ -258,12 +258,17 @@ public String getCharacterEncoding() {
258258 @ Override
259259 public ServletOutputStream getOutputStream () {
260260 Assert .state (this .outputStreamAccessAllowed , "OutputStream access not allowed" );
261+ Assert .state (this .writer == null , "getWriter() has already been called" );
262+ if (this .outputStream == null ) {
263+ this .outputStream = new ResponseServletOutputStream (this .content );
264+ }
261265 return this .outputStream ;
262266 }
263267
264268 @ Override
265269 public PrintWriter getWriter () throws UnsupportedEncodingException {
266270 Assert .state (this .writerAccessAllowed , "Writer access not allowed" );
271+ Assert .state (this .outputStream == null , "getOutputStream() has already been called" );
267272 if (this .writer == null ) {
268273 Writer targetWriter = new OutputStreamWriter (this .content , getCharacterEncoding ());
269274 this .writer = new ResponsePrintWriter (targetWriter );
@@ -365,6 +370,9 @@ else if (mediaType.isCompatibleWith(MediaType.APPLICATION_JSON) ||
365370 }
366371 updateContentTypePropertyAndHeader ();
367372 }
373+ else {
374+ this .headers .remove (HttpHeaders .CONTENT_TYPE );
375+ }
368376 }
369377
370378 @ Override
@@ -421,6 +429,8 @@ public void reset() {
421429 this .headers .clear ();
422430 this .status = HttpServletResponse .SC_OK ;
423431 this .errorMessage = null ;
432+ this .writer = null ;
433+ this .outputStream = null ;
424434 }
425435
426436 @ Override
@@ -680,17 +690,12 @@ private DateFormat newDateFormat() {
680690 }
681691
682692 @ Override
683- public void setHeader (String name , @ Nullable String value ) {
684- if (value == null ) {
685- this .headers .remove (name );
686- }
687- else {
688- setHeaderValue (name , value );
689- }
693+ public void setHeader (@ Nullable String name , @ Nullable String value ) {
694+ setHeaderValue (name , value );
690695 }
691696
692697 @ Override
693- public void addHeader (String name , @ Nullable String value ) {
698+ public void addHeader (@ Nullable String name , @ Nullable String value ) {
694699 addHeaderValue (name , value );
695700 }
696701
@@ -704,8 +709,8 @@ public void addIntHeader(String name, int value) {
704709 addHeaderValue (name , value );
705710 }
706711
707- private void setHeaderValue (String name , @ Nullable Object value ) {
708- if (value == null ) {
712+ private void setHeaderValue (@ Nullable String name , @ Nullable Object value ) {
713+ if (name == null ) {
709714 return ;
710715 }
711716 boolean replaceHeader = true ;
@@ -715,8 +720,8 @@ private void setHeaderValue(String name, @Nullable Object value) {
715720 doAddHeaderValue (name , value , replaceHeader );
716721 }
717722
718- private void addHeaderValue (String name , @ Nullable Object value ) {
719- if (value == null ) {
723+ private void addHeaderValue (@ Nullable String name , @ Nullable Object value ) {
724+ if (name == null ) {
720725 return ;
721726 }
722727 boolean replaceHeader = false ;
@@ -726,7 +731,19 @@ private void addHeaderValue(String name, @Nullable Object value) {
726731 doAddHeaderValue (name , value , replaceHeader );
727732 }
728733
729- private boolean setSpecialHeader (String name , Object value , boolean replaceHeader ) {
734+ private boolean setSpecialHeader (String name , @ Nullable Object value , boolean replaceHeader ) {
735+ if (value == null ) {
736+ if (HttpHeaders .CONTENT_TYPE .equalsIgnoreCase (name )) {
737+ setContentType (null );
738+ }
739+ else if (HttpHeaders .CONTENT_LENGTH .equalsIgnoreCase (name )) {
740+ this .contentLength = 0 ;
741+ }
742+ else {
743+ this .headers .remove (name );
744+ }
745+ return true ;
746+ }
730747 if (HttpHeaders .CONTENT_TYPE .equalsIgnoreCase (name )) {
731748 setContentType (value .toString ());
732749 return true ;
@@ -763,7 +780,7 @@ else if (HttpHeaders.SET_COOKIE.equalsIgnoreCase(name)) {
763780 }
764781 }
765782
766- private void doAddHeaderValue (String name , Object value , boolean replace ) {
783+ private void doAddHeaderValue (String name , @ Nullable Object value , boolean replace ) {
767784 Assert .notNull (value , "Header value must not be null" );
768785 HeaderValueHolder header = this .headers .computeIfAbsent (name , key -> new HeaderValueHolder ());
769786 if (replace ) {
0 commit comments