I have a class,which i use input stream and then conver it to string. Also i have a Junit test,where i get the exception " java.lang.OutOfMemoryError: Java heap space",I know that the problem is that I have a memory leak in the test, but I don’t understand how to fix it.Maybe someone know how to do it?
My class:
public class IntegrationMonitoringHttpInterceptor implements ClientHttpRequestInterceptor
{
private static final Logger LOG = LoggerFactory.getLogger(IntegrationMonitoringHttpInterceptor.class);
@Resource
private IntegrationMessageService integrationMessageService;
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] bytes, final ClientHttpRequestExecution clientHttpRequestExecution) throws IOException
{
final String requestMethod = request.getMethod().toString();
final String requestURI = request.getURI().toString();
final String requestHeaders = request.getHeaders().toString();
final String requestBody = new String(bytes, StandardCharsets.UTF_8);
final String requestMessageBody = requestMethod + "\n" + requestURI + "\n" + requestHeaders + "\n" + requestBody;
final IntegrationMessageBatchModel batch = saveRequest(requestURI, requestMessageBody);
try
{
final ClientHttpResponse response = clientHttpRequestExecution.execute(request, bytes);
final String responseStatusCode = response.getStatusCode().toString();
final String responseStatusText = response.getStatusText();
final String responseHeaders = response.getHeaders().toString();
final InputStream responseInputStream = response.getBody();
final String responseBody = IOUtils.toString(responseInputStream, StandardCharsets.UTF_8.name()); //in the test, a memory leak occurs here
IOUtils.closeQuietly(responseInputStream);
responseInputStream.close();
final String responseMessageBody = responseStatusCode + "\n" + responseStatusText + responseHeaders + "\n" + responseBody;
saveResponse(responseMessageBody, batch, requestURI);
return response;
}
catch (Exception exception)
{
integrationMessageService.createMessageInBatch(exception.getMessage(), batch);
LOG.warn("Cannot execute request due to unexpected error", exception);
throw exception;
}
}
private IntegrationMessageBatchModel saveRequest(final String requestURI, final String requestMessageBody)
{
try
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(requestMessageBody, integrationMessageBatchModel);
return integrationMessageBatchModel;
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
return null;
}
}
private void saveResponse(final String response, final IntegrationMessageBatchModel batchModel, final String requestURI)
{
try
{
if (batchModel != null)
{
integrationMessageService.createMessageInBatch(response, batchModel);
}
else
{
IntegrationMessageBatchModel integrationMessageBatchModel = integrationMessageService.createBatch(IntegrationExchangeType.HTTP, requestURI);
integrationMessageService.createMessageInBatch(response, integrationMessageBatchModel);
}
}
catch (Exception exception)
{
LOG.warn("Cannot save message due to unexpected error", exception);
}
}
}
My JUnit test:
@RunWith(MockitoJUnitRunner.class)
@UnitTest
public class IntegrationMonitoringHttpInterceptorTest
{
@Rule
public ExpectedException thrown = ExpectedException.none();
@Mock
private IntegrationMessageService integrationMessageService;
@Mock
private HttpRequest httpRequest;
@Mock
private ClientHttpRequestExecution clientHttpRequestExecution;
@Mock
private ClientHttpResponse clientHttpResponse;
@InjectMocks
private IntegrationMonitoringHttpInterceptor integrationMonitoringHttpInterceptor = new IntegrationMonitoringHttpInterceptor();
@Test
public void intercept() throws Exception
{
final String body = "http message";
final URI uri = new URI("http://headers.jsontest.com/");
final InputStream inputStream = new InputStream()
{
@Override
public int read()
{
return 0;
}
};
when(httpRequest.getURI()).thenReturn(uri);
when(httpRequest.getMethod()).thenReturn(HttpMethod.POST);
when(httpRequest.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpRequestExecution.execute(httpRequest, body.getBytes(StandardCharsets.UTF_8))).thenReturn(clientHttpResponse);
when(clientHttpResponse.getStatusCode()).thenReturn(HttpStatus.OK);
when(clientHttpResponse.getStatusText()).thenReturn("OK");
when(clientHttpResponse.getHeaders()).thenReturn(new HttpHeaders());
when(clientHttpResponse.getBody()).thenReturn(inputStream);
when(integrationMessageService.createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString())))
.thenReturn(new IntegrationMessageBatchModel());
when(integrationMessageService.createMessageInBatch(eq(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
when(integrationMessageService.createMessageInBatch(contains(body), any(IntegrationMessageBatchModel.class)))
.thenReturn(new IntegrationMessageModel());
integrationMonitoringHttpInterceptor.intercept(httpRequest, body.getBytes(StandardCharsets.UTF_8), clientHttpRequestExecution);
verify(clientHttpRequestExecution, times(1)).execute(httpRequest, body.getBytes(StandardCharsets.UTF_8));
verify(integrationMessageService, times(1)).createBatch(eq(IntegrationExchangeType.HTTP), eq(uri.toString()));
verify(integrationMessageService, times(2)).createMessageInBatch(anyString(), any(IntegrationMessageBatchModel.class));
}
Stacktrace:
java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:2367)
at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:535)
at java.lang.StringBuilder.append(StringBuilder.java:204)
at org.apache.commons.io.output.StringBuilderWriter.write(StringBuilderWriter.java:138)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:2002)
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1980)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1957)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:1907)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:778)
at org.apache.commons.io.IOUtils.toString(IOUtils.java:803)
at core.interceptors.IntegrationMonitoringHttpInterceptor.intercept(IntegrationMonitoringHttpInterceptor.java:48)
at core.interceptors.IntegrationMonitoringHttpInterceptorTest.intercept(IntegrationMonitoringHttpInterceptorTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:110)
at org.junit.rules.RunRules.evaluate(RunRules.java:18)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:69)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:48)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
Your mock input is an infinitely long stream of NUL (zero) bytes. At some point there's an attempt to read all of it into memory, which of course makes you run out of memory because it's infinitely long:
A quick fix is to limit it to a known size like 100 bytes