Browse Source

StreamUtils.emptyInput() for consistent empty InputStream exposure

Issue: SPR-13563
pull/888/head
Juergen Hoeller 11 years ago
parent
commit
66177dfd8c
  1. 4
      spring-context/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java
  2. 18
      spring-core/src/main/java/org/springframework/util/StreamUtils.java
  3. 4
      spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java
  4. 4
      spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java
  5. 4
      spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java
  6. 2
      spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
  7. 6
      spring-web/src/main/java/org/springframework/web/multipart/commons/CommonsMultipartFile.java
  8. 4
      spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java
  9. 21
      spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java

4
spring-context/src/test/java/org/springframework/scripting/support/ResourceScriptSourceTests.java

@ -16,13 +16,13 @@
package org.springframework.scripting.support; package org.springframework.scripting.support;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.io.ByteArrayResource; import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.util.StreamUtils;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.mockito.BDDMockito.*; import static org.mockito.BDDMockito.*;
@ -59,7 +59,7 @@ public class ResourceScriptSourceTests {
// does not support File-based reading; delegates to InputStream-style reading... // does not support File-based reading; delegates to InputStream-style reading...
//resource.getFile(); //resource.getFile();
//mock.setThrowable(new FileNotFoundException()); //mock.setThrowable(new FileNotFoundException());
given(resource.getInputStream()).willReturn(new ByteArrayInputStream(new byte[0])); given(resource.getInputStream()).willReturn(StreamUtils.emptyInput());
ResourceScriptSource scriptSource = new ResourceScriptSource(resource); ResourceScriptSource scriptSource = new ResourceScriptSource(resource);
assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified()); assertTrue("ResourceScriptSource must start off in the 'isModified' state (it obviously isn't).", scriptSource.isModified());

18
spring-core/src/main/java/org/springframework/util/StreamUtils.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2013 the original author or authors. * Copyright 2002-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,6 +16,7 @@
package org.springframework.util; package org.springframework.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.FilterOutputStream; import java.io.FilterOutputStream;
@ -43,6 +44,8 @@ public abstract class StreamUtils {
public static final int BUFFER_SIZE = 4096; public static final int BUFFER_SIZE = 4096;
private static final byte[] EMPTY_CONTENT = new byte[0];
/** /**
* Copy the contents of the given InputStream into a new byte array. * Copy the contents of the given InputStream into a new byte array.
@ -129,7 +132,16 @@ public abstract class StreamUtils {
} }
/** /**
* Returns a variant of the given {@link InputStream} where calling * Return an efficient empty {@link InputStream}.
* @return a {@link ByteArrayInputStream} based on an empty byte array
* @since 4.2.2
*/
public static InputStream emptyInput() {
return new ByteArrayInputStream(EMPTY_CONTENT);
}
/**
* Return a variant of the given {@link InputStream} where calling
* {@link InputStream#close() close()} has no effect. * {@link InputStream#close() close()} has no effect.
* @param in the InputStream to decorate * @param in the InputStream to decorate
* @return a version of the InputStream that ignores calls to close * @return a version of the InputStream that ignores calls to close
@ -140,7 +152,7 @@ public abstract class StreamUtils {
} }
/** /**
* Returns a variant of the given {@link OutputStream} where calling * Return a variant of the given {@link OutputStream} where calling
* {@link OutputStream#close() close()} has no effect. * {@link OutputStream#close() close()} has no effect.
* @param out the OutputStream to decorate * @param out the OutputStream to decorate
* @return a version of the OutputStream that ignores calls to close * @return a version of the OutputStream that ignores calls to close

4
spring-test/src/main/java/org/springframework/mock/web/MockHttpServletRequest.java

@ -39,7 +39,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
@ -59,6 +58,7 @@ import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -122,7 +122,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private static final String CHARSET_PREFIX = "charset="; private static final String CHARSET_PREFIX = "charset=";
private static final ServletInputStream EMPTY_SERVLET_INPUT_STREAM = private static final ServletInputStream EMPTY_SERVLET_INPUT_STREAM =
new DelegatingServletInputStream(new ByteArrayInputStream(new byte[0])); new DelegatingServletInputStream(StreamUtils.emptyInput());
/** /**
* Date formats as specified in the HTTP RFC * Date formats as specified in the HTTP RFC

4
spring-web/src/main/java/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java

@ -16,7 +16,6 @@
package org.springframework.http.converter.json; package org.springframework.http.converter.json;
import java.io.ByteArrayInputStream;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
@ -54,6 +53,7 @@ import org.springframework.beans.FatalBeanException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -761,7 +761,7 @@ public class Jackson2ObjectMapperBuilder {
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
@Override @Override
public Object resolveEntity(String publicID, String systemID, String base, String ns) { public Object resolveEntity(String publicID, String systemID, String base, String ns) {
return new ByteArrayInputStream(new byte[0]); return StreamUtils.emptyInput();
} }
}; };
} }

4
spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java

@ -16,7 +16,6 @@
package org.springframework.http.converter.xml; package org.springframework.http.converter.xml;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@ -46,6 +45,7 @@ import org.springframework.http.converter.GenericHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConversionException; import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException; import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.StreamUtils;
/** /**
* An {@code HttpMessageConverter} that can read XML collections using JAXB2. * An {@code HttpMessageConverter} that can read XML collections using JAXB2.
@ -256,7 +256,7 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
@Override @Override
public Object resolveEntity(String publicID, String systemID, String base, String ns) { public Object resolveEntity(String publicID, String systemID, String base, String ns) {
return new ByteArrayInputStream(new byte[0]); return StreamUtils.emptyInput();
} }
}; };

2
spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java

@ -289,7 +289,7 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() { private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
@Override @Override
public Object resolveEntity(String publicID, String systemID, String base, String ns) { public Object resolveEntity(String publicID, String systemID, String base, String ns) {
return new ByteArrayInputStream(new byte[0]); return StreamUtils.emptyInput();
} }
}; };

6
spring-web/src/main/java/org/springframework/web/multipart/commons/CommonsMultipartFile.java

@ -16,7 +16,6 @@
package org.springframework.web.multipart.commons; package org.springframework.web.multipart.commons;
import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -28,10 +27,11 @@ import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.util.StreamUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
/** /**
* MultipartFile implementation for Apache Commons FileUpload. * {@link MultipartFile} implementation for Apache Commons FileUpload.
* *
* @author Trevor D. Cook * @author Trevor D. Cook
* @author Juergen Hoeller * @author Juergen Hoeller
@ -124,7 +124,7 @@ public class CommonsMultipartFile implements MultipartFile, Serializable {
throw new IllegalStateException("File has been moved - cannot be read again"); throw new IllegalStateException("File has been moved - cannot be read again");
} }
InputStream inputStream = this.fileItem.getInputStream(); InputStream inputStream = this.fileItem.getInputStream();
return (inputStream != null ? inputStream : new ByteArrayInputStream(new byte[0])); return (inputStream != null ? inputStream : StreamUtils.emptyInput());
} }
@Override @Override

4
spring-web/src/test/java/org/springframework/mock/web/test/MockHttpServletRequest.java

@ -39,7 +39,6 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TimeZone; import java.util.TimeZone;
import javax.servlet.AsyncContext; import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
@ -59,6 +58,7 @@ import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap; import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -122,7 +122,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private static final String CHARSET_PREFIX = "charset="; private static final String CHARSET_PREFIX = "charset=";
private static final ServletInputStream EMPTY_SERVLET_INPUT_STREAM = private static final ServletInputStream EMPTY_SERVLET_INPUT_STREAM =
new DelegatingServletInputStream(new ByteArrayInputStream(new byte[0])); new DelegatingServletInputStream(StreamUtils.emptyInput());
/** /**
* Date formats as specified in the HTTP RFC * Date formats as specified in the HTTP RFC

21
spring-web/src/test/java/org/springframework/web/filter/ShallowEtagHeaderFilterTests.java

@ -16,16 +16,15 @@
package org.springframework.web.filter; package org.springframework.web.filter;
import java.io.ByteArrayInputStream;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.util.StreamUtils;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -36,27 +35,23 @@ import static org.junit.Assert.*;
*/ */
public class ShallowEtagHeaderFilterTests { public class ShallowEtagHeaderFilterTests {
private ShallowEtagHeaderFilter filter; private final ShallowEtagHeaderFilter filter = new ShallowEtagHeaderFilter();
@Before
public void createFilter() throws Exception {
filter = new ShallowEtagHeaderFilter();
}
@Test @Test
public void isEligibleForEtag() { public void isEligibleForEtag() {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
assertTrue(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0]))); assertTrue(filter.isEligibleForEtag(request, response, 200, StreamUtils.emptyInput()));
assertFalse(filter.isEligibleForEtag(request, response, 300, new ByteArrayInputStream(new byte[0]))); assertFalse(filter.isEligibleForEtag(request, response, 300, StreamUtils.emptyInput()));
request = new MockHttpServletRequest("POST", "/hotels"); request = new MockHttpServletRequest("POST", "/hotels");
assertFalse(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0]))); assertFalse(filter.isEligibleForEtag(request, response, 200, StreamUtils.emptyInput()));
request = new MockHttpServletRequest("POST", "/hotels"); request = new MockHttpServletRequest("POST", "/hotels");
request.addHeader("Cache-Control","must-revalidate, no-store"); request.addHeader("Cache-Control","must-revalidate, no-store");
assertFalse(filter.isEligibleForEtag(request, response, 200, new ByteArrayInputStream(new byte[0]))); assertFalse(filter.isEligibleForEtag(request, response, 200, StreamUtils.emptyInput()));
} }
@Test @Test
@ -120,9 +115,7 @@ public class ShallowEtagHeaderFilterTests {
assertArrayEquals("Invalid content", new byte[0], response.getContentAsByteArray()); assertArrayEquals("Invalid content", new byte[0], response.getContentAsByteArray());
} }
// SPR-12960 @Test // SPR-12960
@Test
public void filterWriterWithDisabledCaching() throws Exception { public void filterWriterWithDisabledCaching() throws Exception {
final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); final MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();

Loading…
Cancel
Save