一个过程是创建一个json文档序列的日志。另一个进程想要在生成日志时读取它(类似于tail -f)并使用Jackson JsonParser(和ObjectReader)解析它。当Reader.read暂时返回-1时,你如何要求JsonParser或MappingIterator不关闭?
尝试通过EOF经常在Reader上创建JsonReader.readValues的示例:
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.junit.Test;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
public class ParitalParserTest {
/** Reader that temporarily returns -1 (EOF) to simulate growing file */
private static class StringReaderWithEofs extends Reader {
public final String string;
private int pos;
private int limit;
public StringReaderWithEofs(String string) {
this.string = string;
}
public void limit(int limit) {
this.limit = limit;
}
@Override public int read(char[] cbuf, int off, int len) throws IOException {
int newPos = Math.min(pos + len, limit);
string.getChars(pos, newPos, cbuf, off);
int r = newPos - this.pos;
if (r == 0) r = -1;
this.pos = newPos;
return r;
}
@Override public void close() throws IOException {}
}
/** POJO log event */
public static class LogEvent {
private final String message;
@JsonCreator
public LogEvent(@JsonProperty("message") String message) {
this.message = message;
}
public String getMessage() {
return message;
}
@Override public int hashCode() {
return Objects.hash(message);
}
@Override public boolean equals(Object obj) {
if (! (obj instanceof LogEvent) || obj.getClass() != this.getClass()) return false;
LogEvent o = (LogEvent) obj;
return Objects.equals(message, o.message);
}
@Override public String toString() {
return String.format("%s{message=%s}", getClass().getSimpleName(), message);
}
}
public void test(boolean withEofs) throws IOException {
ObjectMapper mapper = new ObjectMapper();
ObjectReader jsonReader = mapper.reader(LogEvent.class);
String one = "{\"message\":\"one\"}\n";
String two = "{\"message\":\"two\"}\n";
String three = "{\"message\":\"three\"}\n";
StringReaderWithEofs reader = new StringReaderWithEofs(one + two + three);
MappingIterator<LogEvent> it = null;
List<LogEvent> values = new ArrayList<>();
int firstLimit = withEofs ? 1 : reader.string.length();
int lastLimit = reader.string.length();
for (int i = firstLimit; i <= lastLimit; i++) {
reader.limit(i);
if (it == null) {
it = jsonReader.readValues(reader);
}
while (it.hasNext()) {
LogEvent value = it.next();
values.add(value);
}
}
List<LogEvent> expected = Arrays.asList(new LogEvent("one"), new LogEvent("two"), new LogEvent("three"));
assertEquals(expected, values);
}
@Test public void testReadFullFile() throws IOException {
test(false);
}
@Test public void testReadPartialFile() throws IOException {
test(true);
}
}
答案 0 :(得分:3)
这有点棘手,但我可能会尝试创建一个Reader
,如果没有数据可用,实际阻塞,睡眠,检查等等。这样杰克逊就不必担心缺乏内容。
从Reader
或InputStream
返回0实际上并没有帮助,因为解析器无法做很多事情,因为实际上没有办法正确阻止。或者,换句话说:底层读者或流必须尝试读取至少一个字节(如果一个或多个请求),如果没有找到则阻塞;如果没有可用的话,则返回-1。