1 package com.fasterxml.jackson.databind; 2 3 import java.io.ByteArrayOutputStream; 4 import java.io.Closeable; 5 import java.io.IOException; 6 import java.io.StringWriter; 7 import java.util.*; 8 9 import com.fasterxml.jackson.annotation.JsonTypeInfo; 10 import com.fasterxml.jackson.annotation.JsonTypeName; 11 12 import com.fasterxml.jackson.core.*; 13 import com.fasterxml.jackson.core.io.SerializedString; 14 import com.fasterxml.jackson.core.json.JsonWriteFeature; 15 import com.fasterxml.jackson.databind.node.ObjectNode; 16 17 /** 18 * Unit tests for checking features added to {@link ObjectWriter}, such 19 * as adding of explicit pretty printer. 20 */ 21 public class ObjectWriterTest 22 extends BaseMapTest 23 { 24 static class CloseableValue implements Closeable 25 { 26 public int x; 27 28 public boolean closed; 29 30 @Override close()31 public void close() throws IOException { 32 closed = true; 33 } 34 } 35 36 final ObjectMapper MAPPER = new ObjectMapper(); 37 38 @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") 39 static class PolyBase { 40 } 41 42 @JsonTypeName("A") 43 static class ImplA extends PolyBase { 44 public int value; 45 ImplA(int v)46 public ImplA(int v) { value = v; } 47 } 48 49 @JsonTypeName("B") 50 static class ImplB extends PolyBase { 51 public int b; 52 ImplB(int v)53 public ImplB(int v) { b = v; } 54 } 55 56 /* 57 /********************************************************** 58 /* Test methods, normal operation 59 /********************************************************** 60 */ 61 testPrettyPrinter()62 public void testPrettyPrinter() throws Exception 63 { 64 ObjectWriter writer = MAPPER.writer(); 65 HashMap<String, Integer> data = new HashMap<String,Integer>(); 66 data.put("a", 1); 67 68 // default: no indentation 69 assertEquals("{\"a\":1}", writer.writeValueAsString(data)); 70 71 // and then with standard 72 writer = writer.withDefaultPrettyPrinter(); 73 74 // pretty printer uses system-specific line feeds, so we do that as well. 75 String lf = System.getProperty("line.separator"); 76 assertEquals("{" + lf + " \"a\" : 1" + lf + "}", writer.writeValueAsString(data)); 77 78 // and finally, again without indentation 79 writer = writer.with((PrettyPrinter) null); 80 assertEquals("{\"a\":1}", writer.writeValueAsString(data)); 81 } 82 testPrefetch()83 public void testPrefetch() throws Exception 84 { 85 ObjectWriter writer = MAPPER.writer(); 86 assertFalse(writer.hasPrefetchedSerializer()); 87 writer = writer.forType(String.class); 88 assertTrue(writer.hasPrefetchedSerializer()); 89 } 90 testObjectWriterFeatures()91 public void testObjectWriterFeatures() throws Exception 92 { 93 ObjectWriter writer = MAPPER.writer() 94 .without(JsonWriteFeature.QUOTE_FIELD_NAMES); 95 Map<String,Integer> map = new HashMap<String,Integer>(); 96 map.put("a", 1); 97 assertEquals("{a:1}", writer.writeValueAsString(map)); 98 // but can also reconfigure 99 assertEquals("{\"a\":1}", writer.with(JsonWriteFeature.QUOTE_FIELD_NAMES) 100 .writeValueAsString(map)); 101 } 102 testObjectWriterWithNode()103 public void testObjectWriterWithNode() throws Exception 104 { 105 ObjectNode stuff = MAPPER.createObjectNode(); 106 stuff.put("a", 5); 107 ObjectWriter writer = MAPPER.writerFor(JsonNode.class); 108 String json = writer.writeValueAsString(stuff); 109 assertEquals("{\"a\":5}", json); 110 } 111 testPolymorphicWithTyping()112 public void testPolymorphicWithTyping() throws Exception 113 { 114 ObjectWriter writer = MAPPER.writerFor(PolyBase.class); 115 String json; 116 117 json = writer.writeValueAsString(new ImplA(3)); 118 assertEquals(aposToQuotes("{'type':'A','value':3}"), json); 119 json = writer.writeValueAsString(new ImplB(-5)); 120 assertEquals(aposToQuotes("{'type':'B','b':-5}"), json); 121 } 122 testCanSerialize()123 public void testCanSerialize() throws Exception 124 { 125 assertTrue(MAPPER.writer().canSerialize(String.class)); 126 assertTrue(MAPPER.writer().canSerialize(String.class, null)); 127 } 128 testNoPrefetch()129 public void testNoPrefetch() throws Exception 130 { 131 ObjectWriter w = MAPPER.writer() 132 .without(SerializationFeature.EAGER_SERIALIZER_FETCH); 133 ByteArrayOutputStream out = new ByteArrayOutputStream(); 134 w.writeValue(out, Integer.valueOf(3)); 135 out.close(); 136 assertEquals("3", out.toString("UTF-8")); 137 } 138 testWithCloseCloseable()139 public void testWithCloseCloseable() throws Exception 140 { 141 ObjectWriter w = MAPPER.writer() 142 .with(SerializationFeature.CLOSE_CLOSEABLE); 143 assertTrue(w.isEnabled(SerializationFeature.CLOSE_CLOSEABLE)); 144 CloseableValue input = new CloseableValue(); 145 assertFalse(input.closed); 146 byte[] json = w.writeValueAsBytes(input); 147 assertNotNull(json); 148 assertTrue(input.closed); 149 input.close(); 150 151 // and via explicitly passed generator 152 JsonGenerator g = MAPPER.createGenerator(new StringWriter()); 153 input = new CloseableValue(); 154 assertFalse(input.closed); 155 w.writeValue(g, input); 156 assertTrue(input.closed); 157 g.close(); 158 input.close(); 159 } 160 testViewSettings()161 public void testViewSettings() throws Exception 162 { 163 ObjectWriter w = MAPPER.writer(); 164 ObjectWriter newW = w.withView(String.class); 165 assertNotSame(w, newW); 166 assertSame(newW, newW.withView(String.class)); 167 168 newW = w.with(Locale.CANADA); 169 assertNotSame(w, newW); 170 assertSame(newW, newW.with(Locale.CANADA)); 171 } 172 testMiscSettings()173 public void testMiscSettings() throws Exception 174 { 175 ObjectWriter w = MAPPER.writer(); 176 assertSame(MAPPER.getFactory(), w.getFactory()); 177 assertFalse(w.hasPrefetchedSerializer()); 178 assertNotNull(w.getTypeFactory()); 179 180 JsonFactory f = new JsonFactory(); 181 w = w.with(f); 182 assertSame(f, w.getFactory()); 183 ObjectWriter newW = w.with(Base64Variants.MODIFIED_FOR_URL); 184 assertNotSame(w, newW); 185 assertSame(newW, newW.with(Base64Variants.MODIFIED_FOR_URL)); 186 187 w = w.withAttributes(Collections.emptyMap()); 188 w = w.withAttribute("a", "b"); 189 assertEquals("b", w.getAttributes().getAttribute("a")); 190 w = w.withoutAttribute("a"); 191 assertNull(w.getAttributes().getAttribute("a")); 192 193 FormatSchema schema = new BogusSchema(); 194 try { 195 newW = w.with(schema); 196 fail("Should not pass"); 197 } catch (IllegalArgumentException e) { 198 verifyException(e, "Cannot use FormatSchema"); 199 } 200 } 201 testRootValueSettings()202 public void testRootValueSettings() throws Exception 203 { 204 ObjectWriter w = MAPPER.writer(); 205 206 // First, root name: 207 ObjectWriter newW = w.withRootName("foo"); 208 assertNotSame(w, newW); 209 assertSame(newW, newW.withRootName(PropertyName.construct("foo"))); 210 w = newW; 211 newW = w.withRootName((String) null); 212 assertNotSame(w, newW); 213 assertSame(newW, newW.withRootName((PropertyName) null)); 214 215 // Then root value separator 216 217 w = w.withRootValueSeparator(new SerializedString(",")); 218 assertSame(w, w.withRootValueSeparator(new SerializedString(","))); 219 assertSame(w, w.withRootValueSeparator(",")); 220 221 newW = w.withRootValueSeparator("/"); 222 assertNotSame(w, newW); 223 assertSame(newW, newW.withRootValueSeparator("/")); 224 225 newW = w.withRootValueSeparator((String) null); 226 assertNotSame(w, newW); 227 228 newW = w.withRootValueSeparator((SerializableString) null); 229 assertNotSame(w, newW); 230 } 231 testFeatureSettings()232 public void testFeatureSettings() throws Exception 233 { 234 ObjectWriter w = MAPPER.writer(); 235 assertFalse(w.isEnabled(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)); 236 assertFalse(w.isEnabled(JsonGenerator.Feature.STRICT_DUPLICATE_DETECTION)); 237 assertFalse(w.isEnabled(StreamWriteFeature.STRICT_DUPLICATE_DETECTION)); 238 239 ObjectWriter newW = w.with(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS, 240 SerializationFeature.INDENT_OUTPUT); 241 assertNotSame(w, newW); 242 assertTrue(newW.isEnabled(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS)); 243 assertTrue(newW.isEnabled(SerializationFeature.INDENT_OUTPUT)); 244 assertSame(newW, newW.with(SerializationFeature.INDENT_OUTPUT)); 245 assertSame(newW, newW.withFeatures(SerializationFeature.INDENT_OUTPUT)); 246 247 newW = w.withFeatures(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS, 248 SerializationFeature.INDENT_OUTPUT); 249 assertNotSame(w, newW); 250 251 newW = w.without(SerializationFeature.FAIL_ON_EMPTY_BEANS, 252 SerializationFeature.EAGER_SERIALIZER_FETCH); 253 assertNotSame(w, newW); 254 assertFalse(newW.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)); 255 assertFalse(newW.isEnabled(SerializationFeature.EAGER_SERIALIZER_FETCH)); 256 assertSame(newW, newW.without(SerializationFeature.FAIL_ON_EMPTY_BEANS)); 257 assertSame(newW, newW.withoutFeatures(SerializationFeature.FAIL_ON_EMPTY_BEANS)); 258 259 assertNotSame(w, w.withoutFeatures(SerializationFeature.FAIL_ON_EMPTY_BEANS, 260 SerializationFeature.EAGER_SERIALIZER_FETCH)); 261 } 262 testGeneratorFeatures()263 public void testGeneratorFeatures() throws Exception 264 { 265 ObjectWriter w = MAPPER.writer(); 266 assertNotSame(w, w.with(JsonWriteFeature.ESCAPE_NON_ASCII)); 267 assertNotSame(w, w.withFeatures(JsonWriteFeature.ESCAPE_NON_ASCII)); 268 269 assertTrue(w.isEnabled(JsonGenerator.Feature.AUTO_CLOSE_TARGET)); 270 assertNotSame(w, w.without(JsonGenerator.Feature.AUTO_CLOSE_TARGET)); 271 assertNotSame(w, w.withoutFeatures(JsonGenerator.Feature.AUTO_CLOSE_TARGET)); 272 273 assertFalse(w.isEnabled(StreamWriteFeature.STRICT_DUPLICATE_DETECTION)); 274 assertNotSame(w, w.with(StreamWriteFeature.STRICT_DUPLICATE_DETECTION)); 275 } 276 277 /* 278 /********************************************************** 279 /* Test methods, failures 280 /********************************************************** 281 */ 282 testArgumentChecking()283 public void testArgumentChecking() throws Exception 284 { 285 final ObjectWriter w = MAPPER.writer(); 286 try { 287 w.acceptJsonFormatVisitor((JavaType) null, null); 288 fail("Should not pass"); 289 } catch (IllegalArgumentException e) { 290 verifyException(e, "argument \"type\" is null"); 291 } 292 } 293 testSchema()294 public void testSchema() throws Exception 295 { 296 try { 297 MAPPER.writerFor(String.class) 298 .with(new BogusSchema()) 299 .writeValueAsBytes("foo"); 300 fail("Should not pass"); 301 } catch (IllegalArgumentException e) { 302 verifyException(e, "Cannot use FormatSchema"); 303 } 304 } 305 } 306