1 package com.fasterxml.jackson.databind.seq; 2 3 import java.io.Closeable; 4 import java.io.IOException; 5 import java.io.StringWriter; 6 import java.util.*; 7 8 import com.fasterxml.jackson.annotation.JsonPropertyOrder; 9 import com.fasterxml.jackson.annotation.JsonTypeInfo; 10 import com.fasterxml.jackson.annotation.JsonTypeName; 11 12 import com.fasterxml.jackson.core.JsonGenerator; 13 import com.fasterxml.jackson.core.io.SerializedString; 14 15 import com.fasterxml.jackson.databind.*; 16 import com.fasterxml.jackson.databind.json.JsonMapper; 17 18 public class SequenceWriterTest extends BaseMapTest 19 { 20 static class Bean { 21 public int a; 22 Bean(int value)23 public Bean(int value) { a = value; } 24 25 @Override equals(Object o)26 public boolean equals(Object o) { 27 if (o == null || o.getClass() != getClass()) return false; 28 Bean other = (Bean) o; 29 return other.a == this.a; 30 } hashCode()31 @Override public int hashCode() { return a; } 32 } 33 34 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") 35 static class PolyBase { 36 } 37 38 @JsonTypeName("A") 39 static class ImplA extends PolyBase { 40 public int value; 41 ImplA(int v)42 public ImplA(int v) { value = v; } 43 } 44 45 @JsonTypeName("B") 46 static class ImplB extends PolyBase { 47 public int b; 48 ImplB(int v)49 public ImplB(int v) { b = v; } 50 } 51 52 static class BareBase { 53 public int a = 1; 54 } 55 56 @JsonPropertyOrder({ "a", "b" }) 57 static class BareBaseExt extends BareBase { 58 public int b = 2; 59 } 60 61 static class BareBaseCloseable extends BareBase 62 implements Closeable 63 { 64 public int c = 3; 65 66 boolean closed = false; 67 68 @Override close()69 public void close() throws IOException { 70 closed = true; 71 } 72 } 73 74 static class CloseableValue implements Closeable 75 { 76 public int x; 77 78 public boolean closed; 79 80 @Override close()81 public void close() throws IOException { 82 closed = true; 83 } 84 } 85 86 /* 87 /********************************************************** 88 /* Test methods, simple writes 89 /********************************************************** 90 */ 91 92 private final ObjectMapper MAPPER = new ObjectMapper(); 93 private final ObjectWriter WRITER = MAPPER.writer() 94 .withRootValueSeparator("\n"); 95 testSimpleNonArray()96 public void testSimpleNonArray() throws Exception 97 { 98 StringWriter strw = new StringWriter(); 99 SequenceWriter w = WRITER 100 .forType(Bean.class) 101 .writeValues(strw); 102 w.write(new Bean(13)) 103 .write(new Bean(-6)) 104 .writeAll(new Bean[] { new Bean(3), new Bean(1) }) 105 .writeAll(Arrays.asList(new Bean(5), new Bean(7))) 106 ; 107 w.close(); 108 assertEquals(aposToQuotes("{'a':13}\n{'a':-6}\n{'a':3}\n{'a':1}\n{'a':5}\n{'a':7}"), 109 strw.toString()); 110 111 strw = new StringWriter(); 112 JsonGenerator gen = WRITER.createGenerator(strw); 113 w = WRITER 114 .withRootValueSeparator(new SerializedString("/")) 115 .writeValues(gen); 116 w.write(new Bean(1)) 117 .write(new Bean(2)); 118 w.close(); 119 gen.close(); 120 assertEquals(aposToQuotes("{'a':1}/{'a':2}"), 121 strw.toString()); 122 } 123 testSimpleArray()124 public void testSimpleArray() throws Exception 125 { 126 StringWriter strw = new StringWriter(); 127 SequenceWriter w = WRITER.writeValuesAsArray(strw); 128 w.write(new Bean(1)) 129 .write(new Bean(2)) 130 .writeAll(new Bean[] { new Bean(-7), new Bean(2) }); 131 w.close(); 132 assertEquals(aposToQuotes("[{'a':1},{'a':2},{'a':-7},{'a':2}]"), 133 strw.toString()); 134 135 strw = new StringWriter(); 136 JsonGenerator gen = WRITER.createGenerator(strw); 137 w = WRITER.writeValuesAsArray(gen); 138 Collection<Bean> bean = Collections.singleton(new Bean(3)); 139 w.write(new Bean(1)) 140 .write(null) 141 .writeAll((Iterable<Bean>) bean); 142 w.close(); 143 gen.close(); 144 assertEquals(aposToQuotes("[{'a':1},null,{'a':3}]"), 145 strw.toString()); 146 } 147 148 /* 149 /********************************************************** 150 /* Test methods, polymorphic writes 151 /********************************************************** 152 */ 153 154 @SuppressWarnings("resource") testPolymorphicNonArrayWithoutType()155 public void testPolymorphicNonArrayWithoutType() throws Exception 156 { 157 StringWriter strw = new StringWriter(); 158 SequenceWriter w = WRITER 159 .writeValues(strw); 160 w.write(new ImplA(3)) 161 .write(new ImplA(4)) 162 .close(); 163 assertEquals(aposToQuotes("{'type':'A','value':3}\n{'type':'A','value':4}"), 164 strw.toString()); 165 } 166 167 @SuppressWarnings("resource") testPolymorphicArrayWithoutType()168 public void testPolymorphicArrayWithoutType() throws Exception 169 { 170 StringWriter strw = new StringWriter(); 171 SequenceWriter w = WRITER 172 .writeValuesAsArray(strw); 173 w.write(new ImplA(-1)) 174 .write(new ImplA(6)) 175 .close(); 176 assertEquals(aposToQuotes("[{'type':'A','value':-1},{'type':'A','value':6}]"), 177 strw.toString()); 178 } 179 testPolymorphicArrayWithType()180 public void testPolymorphicArrayWithType() throws Exception 181 { 182 StringWriter strw = new StringWriter(); 183 SequenceWriter w = WRITER 184 .forType(PolyBase.class) 185 .writeValuesAsArray(strw); 186 w.write(new ImplA(-1)) 187 .write(new ImplB(3)) 188 .write(new ImplA(7)); 189 w.flush(); 190 w.close(); 191 assertEquals(aposToQuotes("[{'type':'A','value':-1},{'type':'B','b':3},{'type':'A','value':7}]"), 192 strw.toString()); 193 } 194 195 @SuppressWarnings("resource") testSimpleCloseable()196 public void testSimpleCloseable() throws Exception 197 { 198 JsonMapper mapper = JsonMapper.builder().enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY).build(); 199 ObjectWriter w = mapper.writer() 200 .with(SerializationFeature.CLOSE_CLOSEABLE); 201 CloseableValue input = new CloseableValue(); 202 assertFalse(input.closed); 203 StringWriter out = new StringWriter(); 204 SequenceWriter seq = w.writeValues(out); 205 input = new CloseableValue(); 206 assertFalse(input.closed); 207 seq.write(input); 208 assertTrue(input.closed); 209 seq.close(); 210 input.close(); 211 assertEquals(aposToQuotes("{'closed':false,'x':0}"), out.toString()); 212 } 213 testWithExplicitType()214 public void testWithExplicitType() throws Exception 215 { 216 ObjectWriter w = MAPPER.writer() 217 // just for fun (and higher coverage): 218 .without(SerializationFeature.FLUSH_AFTER_WRITE_VALUE) 219 .with(SerializationFeature.CLOSE_CLOSEABLE); 220 StringWriter out = new StringWriter(); 221 SequenceWriter seq = w.writeValues(out); 222 // first full, as-is 223 seq.write(new BareBaseExt()); 224 // but then just base type (no 'b' field) 225 seq.write(new BareBaseExt(), MAPPER.constructType(BareBase.class)); 226 227 // one more. And note! Check for Closeable is for _value_, not type 228 // so it's fine to expect closing here 229 BareBaseCloseable cl = new BareBaseCloseable(); 230 seq.write(cl, MAPPER.constructType(BareBase.class)); 231 assertTrue(cl.closed); 232 cl.close(); 233 234 seq.close(); 235 seq.flush(); 236 assertEquals(aposToQuotes("{'a':1,'b':2} {'a':1} {'a':1}"), out.toString()); 237 } 238 } 239