I use an API (for more info, see below) which accepts an OutputStream to capture data. Instead, I want to provide a Consumer of Strings which consumes the data line after line. Hence I have to write an OutputStream implementation which wraps such a Consumer. This is the easiest I can think of:
import java.io.OutputStream;
import java.util.Objects;
import java.util.function.Consumer;
public class OutputStreamConsumer extends OutputStream {
private final Consumer<String> consumer;
private final StringBuilder sb = new StringBuilder();
public OutputStreamConsumer(Consumer<String> consumer) {
this.consumer = Objects.requireNonNull(consumer);
}
@Override
public void write(int b) {
char c = (char) b;
if (c == '\r') {
return;
}
if (c == '\n') {
consume();
return;
}
this.sb.append(c);
}
@Override
public void close() {
if (sb.length() != 0) {
consume();
}
}
private void consume() {
this.consumer.accept(this.sb.toString());
this.sb.delete(0, Integer.MAX_VALUE);
}
}
However, this is probably not enough for production code in terms of encoding and performance. I think that the necessary logic is already contained in InputStreamReader and BufferedReader but I cannot use these classes in this scenario. What is the best way to write this kind of OutputStream? What jdk classes can I use to avoid writing a bunch of low level code handling encoding, end of lines etc.
Concrete use-case
In a Gradle plugin project, I start an external process using Gradle's project API: ExecSpec. There I can set OutputStreams using the methods setStandardOutput and setErrorOutput in order to capture the output of the process.