diff --git a/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/Stream2JSONInputStream.java b/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/Stream2JSONInputStream.java index 510d13582aa..a7cf8b15f82 100644 --- a/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/Stream2JSONInputStream.java +++ b/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/Stream2JSONInputStream.java @@ -15,11 +15,15 @@ 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 @@ * 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 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 iterator = source.map(e -> GSON.toJson(e)).iterator(); - @Override - public int read() throws IOException { - int result = jsonElementStream.read(); + Enumeration enumeration = new Enumeration<>() { + private boolean consumed = false; + private @Nullable InputStream next = toStream("["); - if (result == -1) { // the current JSON element was completely streamed - if (finished()) { // we are done streaming the collection - return -1; + @Override + public boolean hasMoreElements() { + return next != null || iterator.hasNext(); } - fillBuffer(); // get the next element into a new jsonElementStream - result = jsonElementStream.read(); - } + @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; + } - return result; + private static InputStream toStream(String data) { + return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)); + } + }; + stream = new SequenceInputStream(enumeration); } @Override - public void close() throws IOException { - jsonElementStream.close(); + public int read() throws IOException { + return stream.read(); } - 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)); + @Override + public int read(byte @Nullable [] b, int off, int len) throws IOException { + return stream.read(b, off, len); } - private boolean finished() { - return !firstIteratorElement && !iterator.hasNext(); + @Override + public long transferTo(OutputStream target) throws IOException { + return stream.transferTo(target); + } + + @Override + public void close() throws IOException { + stream.close(); } }