From a3c85ec1364bf0e955e815261003a9a650247ace Mon Sep 17 00:00:00 2001 From: Philippe Marschall Date: Fri, 20 Oct 2023 15:28:32 +0200 Subject: [PATCH 1/2] Verify Jsonb calls close methods The stream based methods in Jsonb specify close being called upon successful completion. Add tests that verify an implementation calls these methods. --- .../tck/json/bind/api/jsonb/JsonbTest.java | 148 +++++++++++++++++- 1 file changed, 141 insertions(+), 7 deletions(-) diff --git a/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java b/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java index 48daeaee..06c0f6b0 100644 --- a/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java +++ b/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024 Oracle and/or its affiliates. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0, which is available at @@ -23,7 +23,9 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; @@ -37,6 +39,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; + /** * @test * @sources JsonbTest.java @@ -131,9 +134,11 @@ public void testFromJsonReaderType() throws IOException { @Test public void testFromJsonStreamClass() throws IOException { try (ByteArrayInputStream stream = new ByteArrayInputStream(TEST_JSON_BYTE)) { - SimpleContainer unmarshalledObject = jsonb.fromJson(stream, SimpleContainer.class); + CloseRememberingInputStream rememberingStream = new CloseRememberingInputStream(stream); + SimpleContainer unmarshalledObject = jsonb.fromJson(rememberingStream, SimpleContainer.class); assertThat("Failed to unmarshal using Jsonb.fromJson method with InputStream and Class arguments.", unmarshalledObject.getInstance(), is(TEST_STRING)); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); } } @@ -148,10 +153,12 @@ public void testFromJsonStreamClass() throws IOException { @Test public void testFromJsonStreamType() throws IOException { try (ByteArrayInputStream stream = new ByteArrayInputStream(TEST_JSON_BYTE)) { + CloseRememberingInputStream rememberingStream = new CloseRememberingInputStream(stream); SimpleContainer unmarshalledObject = jsonb - .fromJson(stream, new SimpleContainer() { }.getClass().getGenericSuperclass()); + .fromJson(rememberingStream, new SimpleContainer() { }.getClass().getGenericSuperclass()); assertThat("Failed to unmarshal using Jsonb.fromJson method with InputStream and Type arguments.", unmarshalledObject.getInstance(), is(TEST_STRING)); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); } } @@ -234,10 +241,12 @@ public void testToJsonObjectTypeWriter() throws IOException { @Test public void testToJsonObjectStream() throws IOException { try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { - jsonb.toJson(new SimpleContainer(), stream); - String jsonString = new String(stream.toByteArray(), StandardCharsets.UTF_8); + CloseRememberingOutputStream rememberingStream = new CloseRememberingOutputStream(stream); + jsonb.toJson(new SimpleContainer(), rememberingStream); + String jsonString = new String(rememberingStream.toByteArray(), StandardCharsets.UTF_8); assertThat("Failed to marshal using Jsonb.toJson method with Object and OutputStream arguments.", jsonString, matchesPattern(MATCHING_PATTERN)); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); } } @@ -252,10 +261,135 @@ public void testToJsonObjectStream() throws IOException { @Test public void testToJsonObjectTypeStream() throws IOException { try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) { - jsonb.toJson(new SimpleContainer(), new SimpleContainer() { }.getClass().getGenericSuperclass(), stream); - String jsonString = new String(stream.toByteArray(), StandardCharsets.UTF_8); + CloseRememberingOutputStream rememberingStream = new CloseRememberingOutputStream(stream); + jsonb.toJson(new SimpleContainer(), new SimpleContainer() { }.getClass().getGenericSuperclass(), rememberingStream); + String jsonString = new String(rememberingStream.toByteArray(), StandardCharsets.UTF_8); assertThat("Failed to marshal using Jsonb.toJson method with Object, Type and OutputStream arguments.", jsonString, matchesPattern(MATCHING_PATTERN)); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); + } + } + + static final class CloseRememberingOutputStream extends OutputStream { + + private ByteArrayOutputStream delegate; + private boolean closeCalled; + + CloseRememberingOutputStream(ByteArrayOutputStream delegate) { + this.delegate = delegate; + this.closeCalled = false; + } + + @Override + public void close() throws IOException { + closeCalled = true; + delegate.close(); + } + + boolean isCloseCalled() { + return closeCalled; + } + + byte[] toByteArray() { + return delegate.toByteArray(); + } + + @Override + public void write(int b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + delegate.write(b, off, len); + } + + } + + static final class CloseRememberingInputStream extends InputStream { + + private InputStream delegate; + private boolean closeCalled; + + CloseRememberingInputStream(InputStream delegate) { + this.delegate = delegate; + this.closeCalled = false; + } + + @Override + public void close() throws IOException { + closeCalled = true; + delegate.close(); } + + boolean isCloseCalled() { + return closeCalled; + } + + @Override + public int read() throws IOException { + return delegate.read(); + } + + public int read(byte[] b) throws IOException { + return delegate.read(b); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + return delegate.read(b, off, len); + } + + @Override + public byte[] readAllBytes() throws IOException { + return delegate.readAllBytes(); + } + + @Override + public byte[] readNBytes(int len) throws IOException { + return delegate.readNBytes(len); + } + + @Override + public int readNBytes(byte[] b, int off, int len) throws IOException { + return delegate.readNBytes(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + return delegate.skip(n); + } + + @Override + public int available() throws IOException { + return delegate.available(); + } + + @Override + public void mark(int readlimit) { + delegate.mark(readlimit); + } + + @Override + public void reset() throws IOException { + delegate.reset(); + } + + @Override + public boolean markSupported() { + return delegate.markSupported(); + } + + @Override + public long transferTo(OutputStream out) throws IOException { + return delegate.transferTo(out); + } + + } } From 1fe8836a06caf80e81fcf436d71c156f32225da0 Mon Sep 17 00:00:00 2001 From: Philippe Marschall Date: Fri, 27 Dec 2024 12:54:22 +0100 Subject: [PATCH 2/2] Fix review comments --- .../tck/json/bind/api/jsonb/JsonbTest.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java b/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java index 06c0f6b0..b15456c2 100644 --- a/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java +++ b/tck/src/main/java/ee/jakarta/tck/json/bind/api/jsonb/JsonbTest.java @@ -246,7 +246,7 @@ public void testToJsonObjectStream() throws IOException { String jsonString = new String(rememberingStream.toByteArray(), StandardCharsets.UTF_8); assertThat("Failed to marshal using Jsonb.toJson method with Object and OutputStream arguments.", jsonString, matchesPattern(MATCHING_PATTERN)); - assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isClosed()); } } @@ -266,28 +266,28 @@ public void testToJsonObjectTypeStream() throws IOException { String jsonString = new String(rememberingStream.toByteArray(), StandardCharsets.UTF_8); assertThat("Failed to marshal using Jsonb.toJson method with Object, Type and OutputStream arguments.", jsonString, matchesPattern(MATCHING_PATTERN)); - assertThat("Failed to close stream upon a successful completion", rememberingStream.isCloseCalled()); + assertThat("Failed to close stream upon a successful completion", rememberingStream.isClosed()); } } - static final class CloseRememberingOutputStream extends OutputStream { + private static final class CloseRememberingOutputStream extends OutputStream { - private ByteArrayOutputStream delegate; - private boolean closeCalled; + private final ByteArrayOutputStream delegate; + private boolean closed; CloseRememberingOutputStream(ByteArrayOutputStream delegate) { this.delegate = delegate; - this.closeCalled = false; + this.closed = false; } @Override public void close() throws IOException { - closeCalled = true; + closed = true; delegate.close(); } - boolean isCloseCalled() { - return closeCalled; + boolean isClosed() { + return closed; } byte[] toByteArray() { @@ -311,9 +311,9 @@ public void write(byte[] b, int off, int len) throws IOException { } - static final class CloseRememberingInputStream extends InputStream { + private static final class CloseRememberingInputStream extends InputStream { - private InputStream delegate; + private final InputStream delegate; private boolean closeCalled; CloseRememberingInputStream(InputStream delegate) { @@ -336,6 +336,7 @@ public int read() throws IOException { return delegate.read(); } + @Override public int read(byte[] b) throws IOException { return delegate.read(b); } @@ -390,6 +391,6 @@ public long transferTo(OutputStream out) throws IOException { return delegate.transferTo(out); } - } + }