This is an automated email from the ASF dual-hosted git repository.
jungm pushed a commit to branch johnzon-1.2.x
in repository https://gitbox.apache.org/repos/asf/johnzon.git
The following commit(s) were added to refs/heads/johnzon-1.2.x by this push:
new a0e5ffdd [JOHNZON-404] don't rely on jdk internals for
BoundedOutputStreamWriter (#128)
a0e5ffdd is described below
commit a0e5ffdd54f7ee80c6ba32bb0aa99e7b44b64e02
Author: Markus Jung <[email protected]>
AuthorDate: Thu Jun 27 14:50:36 2024 +0200
[JOHNZON-404] don't rely on jdk internals for BoundedOutputStreamWriter
(#128)
(cherry picked from commit 89492c9b144995ee3bd3cf243dfe2010bab209cf)
---
.github/workflows/maven.yml | 7 +-
.../johnzon/core/JsonGeneratorFactoryImpl.java | 8 +--
.../main/java/org/apache/johnzon/core/Snippet.java | 14 ++--
.../johnzon/core/io/BoundedOutputStreamWriter.java | 80 ++++++++--------------
.../core/io/BoundedOutputStreamWriterTest.java | 7 +-
5 files changed, 49 insertions(+), 67 deletions(-)
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 4fe88968..78d9d0cb 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -5,18 +5,17 @@ on: [push, pull_request]
jobs:
build:
name: Test with Java ${{ matrix.jdk }}
- #runs-on: ${{ matrix.os }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
- jdk: [ '8', '11', '17', '19' ]
+ jdk: [ '8', '11', '17', '22' ]
dist: [ 'zulu' ]
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK ${{ matrix.jdk }}
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: ${{ matrix.jdk }}
distribution: ${{ matrix.dist }}
diff --git
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
index 646fea4f..0c5a7bb3 100644
---
a/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
+++
b/johnzon-core/src/main/java/org/apache/johnzon/core/JsonGeneratorFactoryImpl.java
@@ -76,10 +76,10 @@ public class JsonGeneratorFactoryImpl extends
AbstractJsonFactory implements Jso
@Override
public JsonGenerator createGenerator(final OutputStream out) {
return new JsonGeneratorImpl(
- boundedOutputStreamWriter <= 0 ?
- new OutputStreamWriter(out, defaultEncoding) :
- new BoundedOutputStreamWriter(out, defaultEncoding,
boundedOutputStreamWriter),
- getBufferProvider(out), pretty);
+ boundedOutputStreamWriter <= 0 ?
+ new OutputStreamWriter(out, defaultEncoding) :
+ new BoundedOutputStreamWriter(out, defaultEncoding,
boundedOutputStreamWriter),
+ getBufferProvider(out), pretty);
}
@Override
diff --git a/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
b/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
index 23ed634c..7beea36e 100644
--- a/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
+++ b/johnzon-core/src/main/java/org/apache/johnzon/core/Snippet.java
@@ -28,6 +28,7 @@ import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.Writer;
+import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
@@ -300,12 +301,13 @@ public class Snippet {
public SnippetWriter(final int max) {
this.max = max;
this.buffer = new ByteArrayOutputStream(max);
- this.mode = new Writing(max, new BoundedOutputStreamWriter(
- buffer,
-
JsonGeneratorFactoryImpl.class.isInstance(generatorFactory) ?
-
JsonGeneratorFactoryImpl.class.cast(generatorFactory).getDefaultEncoding() :
- UTF_8,
- max));
+
+ Charset encoding = UTF_8;
+ if
(JsonGeneratorFactoryImpl.class.isInstance(generatorFactory)) {
+ encoding =
JsonGeneratorFactoryImpl.class.cast(generatorFactory).getDefaultEncoding();
+ }
+
+ this.mode = new Writing(max, new
BoundedOutputStreamWriter(buffer, encoding, max));
}
public String get() {
diff --git
a/johnzon-core/src/main/java/org/apache/johnzon/core/io/BoundedOutputStreamWriter.java
b/johnzon-core/src/main/java/org/apache/johnzon/core/io/BoundedOutputStreamWriter.java
index d0a2100c..897916d5 100644
---
a/johnzon-core/src/main/java/org/apache/johnzon/core/io/BoundedOutputStreamWriter.java
+++
b/johnzon-core/src/main/java/org/apache/johnzon/core/io/BoundedOutputStreamWriter.java
@@ -18,81 +18,61 @@
*/
package org.apache.johnzon.core.io;
+import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.Writer;
-import java.nio.channels.Channels;
import java.nio.charset.Charset;
-import java.nio.charset.CodingErrorAction;
/**
- * {@link java.io.OutputStreamWriter} delegating directly to a {@link
sun.nio.cs.StreamEncoder} with a controlled underlying buffer size.
+ * A {@link BufferedWriter} that wraps an {@link OutputStreamWriter} and
automatically flushes it when flushing its internal buffer.
* It enables to wrap an {@link OutputStream} as a {@link Writer} but with a
faster feedback than a default
- * {@link java.io.OutputStreamWriter} which uses a 8k buffer by default
(encapsulated).
- * <p>
- * Note: the "flush error" can be of 2 characters (lcb in StreamEncoder) but
we can't do much better when encoding.
+ * {@link OutputStreamWriter} which uses a 8k buffer by default (encapsulated).
*/
-public class BoundedOutputStreamWriter extends Writer {
- private final Writer delegate;
+public class BoundedOutputStreamWriter extends BufferedWriter {
+ private final int bufferSize;
- public BoundedOutputStreamWriter(final OutputStream outputStream,
- final Charset charset,
- final int maxSize) {
- delegate = Channels.newWriter(
- Channels.newChannel(outputStream),
- charset.newEncoder()
- .onMalformedInput(CodingErrorAction.REPLACE)
- .onUnmappableCharacter(CodingErrorAction.REPLACE),
- maxSize);
- }
+ private int writtenSinceLastFlush = 0;
- @Override
- public void write(final int c) throws IOException {
- delegate.write(c);
- }
+ public BoundedOutputStreamWriter(OutputStream outputStream, Charset
charset, int maxSize) {
+ super(new OutputStreamWriter(outputStream, charset), maxSize);
- @Override
- public void write(final char[] chars, final int off, final int len) throws
IOException {
- delegate.write(chars, off, len);
+ this.bufferSize = maxSize;
}
- @Override
- public void write(final String str, final int off, final int len) throws
IOException {
- delegate.write(str, off, len);
- }
+ // Only methods that are directly modifying the internal buffer in
BufferedWriter should be overwritten here,
+ // otherwise we might track the same char being written twice
@Override
- public void flush() throws IOException {
- delegate.flush();
- }
+ public void write(String s, int off, int len) throws IOException {
+ autoFlush();
+ super.write(s, off, len);
- @Override
- public void close() throws IOException {
- delegate.close();
+ writtenSinceLastFlush += len;
}
@Override
- public void write(char[] cbuf) throws IOException {
- delegate.write(cbuf);
- }
+ public void write(char[] cbuf, int off, int len) throws IOException {
+ autoFlush();
+ super.write(cbuf, off, len);
- @Override
- public void write(final String str) throws IOException {
- delegate.write(str);
+ writtenSinceLastFlush += len;
}
@Override
- public Writer append(final CharSequence csq) throws IOException {
- return delegate.append(csq);
- }
+ public void write(int c) throws IOException {
+ autoFlush();
+ super.write(c);
- @Override
- public Writer append(final CharSequence csq, final int start, final int
end) throws IOException {
- return delegate.append(csq, start, end);
+ writtenSinceLastFlush += 1;
}
- @Override
- public Writer append(final char c) throws IOException {
- return delegate.append(c);
+ private void autoFlush() throws IOException {
+ if (writtenSinceLastFlush >= bufferSize) {
+ flush();
+
+ writtenSinceLastFlush = 0;
+ }
}
}
diff --git
a/johnzon-core/src/test/java/org/apache/johnzon/core/io/BoundedOutputStreamWriterTest.java
b/johnzon-core/src/test/java/org/apache/johnzon/core/io/BoundedOutputStreamWriterTest.java
index 2b8f6f6c..a10987f8 100644
---
a/johnzon-core/src/test/java/org/apache/johnzon/core/io/BoundedOutputStreamWriterTest.java
+++
b/johnzon-core/src/test/java/org/apache/johnzon/core/io/BoundedOutputStreamWriterTest.java
@@ -22,6 +22,7 @@ import org.junit.Test;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.Writer;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
@@ -31,7 +32,7 @@ public class BoundedOutputStreamWriterTest {
@Test
public void write() throws IOException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- try (final BoundedOutputStreamWriter writer = new
BoundedOutputStreamWriter(outputStream, UTF_8, 10)) {
+ try (final Writer writer = new BoundedOutputStreamWriter(outputStream,
UTF_8, 10)) {
writer.write("ok");
writer.write('1');
}
@@ -42,7 +43,7 @@ public class BoundedOutputStreamWriterTest {
@Test
public void sizeLimit() throws IOException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- try (final BoundedOutputStreamWriter writer = new
BoundedOutputStreamWriter(outputStream, UTF_8, 10)) {
+ try (final Writer writer = new BoundedOutputStreamWriter(outputStream,
UTF_8, 10)) {
writer.write("1234567890");
assertEquals(0, outputStream.size()); // was not yet written since
it matches buffer size
writer.write('1');
@@ -55,7 +56,7 @@ public class BoundedOutputStreamWriterTest {
@Test
public void sizeLimit2() throws IOException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- try (final BoundedOutputStreamWriter writer = new
BoundedOutputStreamWriter(outputStream, UTF_8, 2)) {
+ try (final Writer writer = new BoundedOutputStreamWriter(outputStream,
UTF_8, 10)) {
writer.write("1234567890");
writer.write('1');
}