1 package com.fasterxml.jackson.databind.views; 2 3 import java.io.*; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.*; 7 8 import com.fasterxml.jackson.databind.*; 9 10 /** 11 * Unit tests for verifying JSON view functionality: ability to declaratively 12 * suppress subset of properties from being serialized. 13 */ 14 public class TestViewSerialization 15 extends BaseMapTest 16 { 17 // Classes that represent views 18 static class ViewA { } 19 static class ViewAA extends ViewA { } 20 static class ViewB { } 21 static class ViewBB extends ViewB { } 22 23 static class Bean 24 { 25 @JsonView(ViewA.class) 26 public String a = "1"; 27 28 @JsonView({ViewAA.class, ViewB.class}) 29 public String aa = "2"; 30 31 @JsonView(ViewB.class) getB()32 public String getB() { return "3"; } 33 } 34 35 /** 36 * Bean with mix of explicitly annotated 37 * properties, and implicit ones that may or may 38 * not be included in views. 39 */ 40 static class MixedBean 41 { 42 @JsonView(ViewA.class) 43 public String a = "1"; 44 getB()45 public String getB() { return "2"; } 46 } 47 48 /** 49 * As indicated by [JACKSON-261], @JsonView should imply 50 * that associated element (method, field) is to be considered 51 * a property 52 */ 53 static class ImplicitBean { 54 @JsonView(ViewA.class) 55 private int a = 1; 56 } 57 58 static class VisibilityBean { 59 @JsonProperty protected String id = "id"; 60 61 @JsonView(ViewA.class) 62 public String value = "x"; 63 } 64 65 public static class WebView { } 66 public static class OtherView { } 67 public static class Foo { 68 @JsonView(WebView.class) getFoo()69 public int getFoo() { return 3; } 70 } 71 72 /* 73 /********************************************************** 74 /* Unit tests 75 /********************************************************** 76 */ 77 78 private final ObjectMapper MAPPER = objectMapper(); 79 80 @SuppressWarnings("unchecked") testSimple()81 public void testSimple() throws IOException 82 { 83 StringWriter sw = new StringWriter(); 84 // Ok, first, using no view whatsoever; all 3 85 Bean bean = new Bean(); 86 Map<String,Object> map = writeAndMap(MAPPER, bean); 87 assertEquals(3, map.size()); 88 89 // Then with "ViewA", just one property 90 sw = new StringWriter(); 91 MAPPER.writerWithView(ViewA.class).writeValue(sw, bean); 92 map = MAPPER.readValue(sw.toString(), Map.class); 93 assertEquals(1, map.size()); 94 assertEquals("1", map.get("a")); 95 96 // "ViewAA", 2 properties 97 sw = new StringWriter(); 98 MAPPER.writerWithView(ViewAA.class).writeValue(sw, bean); 99 map = MAPPER.readValue(sw.toString(), Map.class); 100 assertEquals(2, map.size()); 101 assertEquals("1", map.get("a")); 102 assertEquals("2", map.get("aa")); 103 104 // "ViewB", 2 prop2 105 String json = MAPPER.writerWithView(ViewB.class).writeValueAsString(bean); 106 map = MAPPER.readValue(json, Map.class); 107 assertEquals(2, map.size()); 108 assertEquals("2", map.get("aa")); 109 assertEquals("3", map.get("b")); 110 111 // and "ViewBB", 2 as well 112 json = MAPPER.writerWithView(ViewBB.class).writeValueAsString(bean); 113 map = MAPPER.readValue(json, Map.class); 114 assertEquals(2, map.size()); 115 assertEquals("2", map.get("aa")); 116 assertEquals("3", map.get("b")); 117 118 // and finally, without view. 119 json = MAPPER.writerWithView(null).writeValueAsString(bean); 120 map = MAPPER.readValue(json, Map.class); 121 assertEquals(3, map.size()); 122 } 123 124 /** 125 * Unit test to verify implementation of [JACKSON-232], to 126 * allow "opt-in" handling for JSON Views: that is, that 127 * default for properties is to exclude unless included in 128 * a view. 129 */ 130 @SuppressWarnings("unchecked") testDefaultExclusion()131 public void testDefaultExclusion() throws IOException 132 { 133 MixedBean bean = new MixedBean(); 134 135 // default setting: both fields will get included 136 String json = MAPPER.writerWithView(ViewA.class).writeValueAsString(bean); 137 Map<String,Object> map = MAPPER.readValue(json, Map.class); 138 assertEquals(2, map.size()); 139 assertEquals("1", map.get("a")); 140 assertEquals("2", map.get("b")); 141 142 // but can also change (but not necessarily on the fly...) 143 ObjectMapper mapper = jsonMapperBuilder() 144 .configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false) 145 .build(); 146 147 // with this setting, only explicit inclusions count: 148 json = mapper.writerWithView(ViewA.class).writeValueAsString(bean); 149 map = mapper.readValue(json, Map.class); 150 assertEquals(1, map.size()); 151 assertEquals("1", map.get("a")); 152 assertNull(map.get("b")); 153 154 // but without view, view processing disabled: 155 json = mapper.writer().withView(null).writeValueAsString(bean); 156 map = mapper.readValue(json, Map.class); 157 assertEquals(2, map.size()); 158 assertEquals("1", map.get("a")); 159 assertEquals("2", map.get("b")); 160 } 161 162 /** 163 * As per [JACKSON-261], @JsonView annotation should imply that associated 164 * method/field does indicate a property. 165 */ testImplicitAutoDetection()166 public void testImplicitAutoDetection() throws Exception 167 { 168 assertEquals("{\"a\":1}", 169 MAPPER.writeValueAsString(new ImplicitBean())); 170 } 171 testVisibility()172 public void testVisibility() throws Exception 173 { 174 VisibilityBean bean = new VisibilityBean(); 175 // Without view setting, should only see "id" 176 String json = MAPPER.writerWithView(Object.class).writeValueAsString(bean); 177 //json = mapper.writeValueAsString(bean); 178 assertEquals("{\"id\":\"id\"}", json); 179 } 180 181 // [JACKSON-868] test868()182 public void test868() throws IOException 183 { 184 ObjectMapper mapper = new ObjectMapper(); 185 mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT); 186 String json = mapper.writerWithView(OtherView.class).writeValueAsString(new Foo()); 187 assertEquals(json, "{}"); 188 } 189 } 190