Skip to content

Commit 9666f9b

Browse files
authored
Merge pull request #112 from vboulaye/closed-stream-when-autoclose-disabled
fix #99 do not close stream when autoclose is disabled in yaml generator/parser
2 parents 220203d + 97952f0 commit 9666f9b

File tree

4 files changed

+216
-2
lines changed

4 files changed

+216
-2
lines changed

yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLGenerator.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,21 @@ public void close() throws IOException
451451
_emitter.emit(new DocumentEndEvent(null, null, false));
452452
_emitter.emit(new StreamEndEvent(null, null));
453453
super.close();
454-
_writer.close();
454+
455+
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
456+
* on the underlying Reader, unless we "own" it, or auto-closing
457+
* feature is enabled.
458+
* One downside: when using UTF8Writer, underlying buffer(s)
459+
* may not be properly recycled if we don't close the writer.
460+
*/
461+
if (_writer != null) {
462+
if (_ioContext.isResourceManaged() || isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)) {
463+
_writer.close();
464+
} else if (isEnabled(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM)) {
465+
// If we can't close it, we should at least flush
466+
_writer.flush();
467+
}
468+
}
455469
}
456470
}
457471

yaml/src/main/java/com/fasterxml/jackson/dataformat/yaml/YAMLParser.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,16 @@ public Version version() {
216216

217217
@Override
218218
protected void _closeInput() throws IOException {
219-
_reader.close();
219+
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
220+
* on the underlying Reader, unless we "own" it, or auto-closing
221+
* feature is enabled.
222+
* One downside is that when using our optimized
223+
* Reader (granted, we only do that for UTF-32...) this
224+
* means that buffer recycling won't work correctly.
225+
*/
226+
if (_ioContext.isResourceManaged() || isEnabled(JsonParser.Feature.AUTO_CLOSE_SOURCE)) {
227+
_reader.close();
228+
}
220229
}
221230

222231
/*
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.fasterxml.jackson.dataformat.yaml.deser;
2+
3+
import java.io.ByteArrayInputStream;
4+
import java.io.IOException;
5+
import java.io.StringReader;
6+
7+
import org.junit.Assert;
8+
9+
import com.fasterxml.jackson.core.JsonParser;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
12+
13+
public class ParserAutoCloseTest extends ModuleTestBase {
14+
15+
public void testParseReaderWithAutoClose() throws IOException {
16+
ObjectMapper yamlMapper = newObjectMapper();
17+
18+
CloseTrackerReader reader = new CloseTrackerReader("foo:bar");
19+
yamlMapper.readTree(reader);
20+
21+
Assert.assertEquals(true, reader.isClosed());
22+
}
23+
24+
public void testParseStreamWithAutoClose() throws IOException {
25+
ObjectMapper yamlMapper = newObjectMapper();
26+
27+
CloseTrackerOutputStream stream = new CloseTrackerOutputStream("foo:bar");
28+
yamlMapper.readTree(stream);
29+
30+
Assert.assertEquals(true, stream.isClosed());
31+
}
32+
33+
public void testParseReaderWithoutAutoClose() throws IOException {
34+
ObjectMapper yamlMapper = newObjectMapper()
35+
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
36+
37+
CloseTrackerReader reader = new CloseTrackerReader("foo:bar");
38+
yamlMapper.readTree(reader);
39+
40+
Assert.assertEquals(false, reader.isClosed());
41+
}
42+
43+
44+
public void testParseStreamWithoutAutoClose() throws IOException {
45+
ObjectMapper yamlMapper = newObjectMapper()
46+
.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);
47+
48+
CloseTrackerOutputStream stream = new CloseTrackerOutputStream("foo:bar");
49+
yamlMapper.readTree(stream);
50+
51+
Assert.assertEquals(false, stream.isClosed());
52+
}
53+
54+
public static class CloseTrackerReader extends StringReader {
55+
private boolean closed;
56+
57+
public CloseTrackerReader(String s) {
58+
super(s);
59+
}
60+
61+
@Override
62+
public void close() {
63+
closed = true;
64+
super.close();
65+
}
66+
67+
public boolean isClosed() {
68+
return closed;
69+
}
70+
}
71+
72+
73+
public static class CloseTrackerOutputStream extends ByteArrayInputStream {
74+
private boolean closed;
75+
76+
public CloseTrackerOutputStream(String s) {
77+
super(s.getBytes());
78+
}
79+
80+
@Override
81+
public void close() throws IOException {
82+
closed = true;
83+
super.close();
84+
}
85+
86+
public boolean isClosed() {
87+
return closed;
88+
}
89+
}
90+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package com.fasterxml.jackson.dataformat.yaml.ser;
2+
3+
import java.io.IOException;
4+
import java.io.OutputStream;
5+
import java.io.StringWriter;
6+
7+
import org.junit.Assert;
8+
9+
import com.fasterxml.jackson.core.JsonGenerator;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import com.fasterxml.jackson.dataformat.yaml.ModuleTestBase;
12+
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
13+
14+
public class GeneratorAutoCloseTest extends ModuleTestBase {
15+
16+
private Pojo pojo = new Pojo("bar");
17+
18+
public void testGenerateWriterWithoAutoCloseTarget() throws IOException {
19+
CloseTrackerWriter writer = new CloseTrackerWriter();
20+
ObjectMapper yamlMapper = newObjectMapper();
21+
yamlMapper.writeValue(writer, pojo);
22+
Assert.assertEquals(true, writer.isClosed());
23+
}
24+
25+
public void testGenerateOutputStreamWithAutoCloseTarget() throws IOException {
26+
CloseTrackerOutputStream stream = new CloseTrackerOutputStream();
27+
ObjectMapper yamlMapper = newObjectMapper();
28+
yamlMapper.writeValue(stream, pojo);
29+
Assert.assertEquals(true, stream.isClosed());
30+
}
31+
32+
public void testGenerateWriterWithoutAutoCloseTarget() throws IOException {
33+
CloseTrackerWriter writer = new CloseTrackerWriter();
34+
ObjectMapper yamlMapper = newObjectMapper()
35+
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
36+
yamlMapper.writeValue(writer, pojo);
37+
Assert.assertEquals(false, writer.isClosed());
38+
}
39+
40+
public void testGenerateOutputStreamWithoutAutoCloseTarget() throws IOException {
41+
CloseTrackerOutputStream stream = new CloseTrackerOutputStream();
42+
ObjectMapper yamlMapper = newObjectMapper()
43+
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
44+
yamlMapper.writeValue(stream, pojo);
45+
Assert.assertEquals(false, stream.isClosed());
46+
}
47+
48+
public void testGenerateOutputStreamWithoutAutoCloseTargetOnFactory() throws IOException {
49+
CloseTrackerOutputStream stream = new CloseTrackerOutputStream();
50+
ObjectMapper yamlMapper = new ObjectMapper(
51+
new YAMLFactory()
52+
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
53+
);
54+
yamlMapper.writeValue(stream, pojo);
55+
Assert.assertEquals(false, stream.isClosed());
56+
}
57+
58+
59+
static class CloseTrackerOutputStream extends OutputStream {
60+
private boolean closed;
61+
62+
@Override
63+
public void write(int b) throws IOException {
64+
65+
}
66+
67+
@Override
68+
public void close() throws IOException {
69+
closed = true;
70+
super.close();
71+
}
72+
73+
public boolean isClosed() {
74+
return closed;
75+
}
76+
}
77+
78+
static class CloseTrackerWriter extends StringWriter {
79+
private boolean closed;
80+
81+
82+
@Override
83+
public void close() throws IOException {
84+
closed = true;
85+
super.close();
86+
}
87+
88+
public boolean isClosed() {
89+
return closed;
90+
}
91+
}
92+
93+
static class Pojo {
94+
95+
public final String foo;
96+
97+
Pojo(final String foo) {
98+
this.foo = foo;
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)