[rest] refactored the Stream2JSONInputStream to simplify the logic (#4099)

Signed-off-by: Jörg Sautter <joerg.sautter@gmx.net>
This commit is contained in:
joerg1985
2024-03-10 17:24:01 +01:00
committed by GitHub
parent 977fa0329a
commit 3d83c70184
@@ -15,11 +15,15 @@ package org.openhab.core.io.rest;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.SequenceInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.library.types.DateTimeType;
import com.google.gson.Gson;
@@ -32,17 +36,14 @@ import com.google.gson.GsonBuilder;
* nested collections JSON representation will be fully transformed into memory.
*
* @author Henning Treu - Initial contribution
* @author Jörg Sautter - Use as SequenceInputStream to simplify the logic
*/
@NonNullByDefault
public class Stream2JSONInputStream extends InputStream implements JSONInputStream {
private final Iterator<String> iterator;
private static final Gson GSON = new GsonBuilder().setDateFormat(DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS).create();
private InputStream jsonElementStream;
private boolean firstIteratorElement;
private final Gson gson = new GsonBuilder().setDateFormat(DateTimeType.DATE_PATTERN_WITH_TZ_AND_MS).create();
private final InputStream stream;
/**
* Creates a new {@link Stream2JSONInputStream} backed by the given {@link Stream} source.
@@ -50,56 +51,68 @@ public class Stream2JSONInputStream extends InputStream implements JSONInputStre
* @param source the {@link Stream} backing this input stream. Must not be null.
*/
public Stream2JSONInputStream(Stream<?> source) {
iterator = source.map(e -> gson.toJson(e)).iterator();
jsonElementStream = new ByteArrayInputStream(new byte[0]);
firstIteratorElement = true;
Iterator<String> iterator = source.map(e -> GSON.toJson(e)).iterator();
Enumeration<InputStream> enumeration = new Enumeration<>() {
private boolean consumed = false;
private @Nullable InputStream next = toStream("[");
@Override
public boolean hasMoreElements() {
return next != null || iterator.hasNext();
}
@Override
public InputStream nextElement() {
InputStream is;
if (next != null) {
is = next;
if (!consumed && !iterator.hasNext()) {
next = toStream("]");
consumed = true;
} else {
next = null;
}
return is;
}
is = toStream(iterator.next());
if (iterator.hasNext()) {
next = toStream(",");
} else {
next = toStream("]");
consumed = true;
}
return is;
}
private static InputStream toStream(String data) {
return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
}
};
stream = new SequenceInputStream(enumeration);
}
@Override
public int read() throws IOException {
int result = jsonElementStream.read();
return stream.read();
}
if (result == -1) { // the current JSON element was completely streamed
if (finished()) { // we are done streaming the collection
return -1;
}
@Override
public int read(byte @Nullable [] b, int off, int len) throws IOException {
return stream.read(b, off, len);
}
fillBuffer(); // get the next element into a new jsonElementStream
result = jsonElementStream.read();
}
return result;
@Override
public long transferTo(OutputStream target) throws IOException {
return stream.transferTo(target);
}
@Override
public void close() throws IOException {
jsonElementStream.close();
}
private void fillBuffer() {
String prefix;
if (firstIteratorElement) {
prefix = "[";
firstIteratorElement = false;
} else {
prefix = ",";
}
String entity = iterator.hasNext() ? iterator.next() : "";
String postfix = "";
if (!iterator.hasNext()) {
postfix = "]";
}
try {
jsonElementStream.close();
} catch (IOException e) {
}
jsonElementStream = new ByteArrayInputStream((prefix + entity + postfix).getBytes(StandardCharsets.UTF_8));
}
private boolean finished() {
return !firstIteratorElement && !iterator.hasNext();
stream.close();
}
}