1 package com.fasterxml.jackson.databind.ser; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.annotation.*; 7 import com.fasterxml.jackson.core.JsonGenerator; 8 import com.fasterxml.jackson.databind.*; 9 import com.fasterxml.jackson.databind.ser.impl.*; 10 import com.fasterxml.jackson.databind.annotation.JsonSerialize; 11 import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer; 12 import com.fasterxml.jackson.databind.ser.std.StdSerializer; 13 14 public class AnyGetterTest extends BaseMapTest 15 { 16 static class Bean 17 { 18 final static Map<String,Boolean> extra = new HashMap<String,Boolean>(); 19 static { 20 extra.put("a", Boolean.TRUE); 21 } 22 getX()23 public int getX() { return 3; } 24 25 @JsonAnyGetter getExtra()26 public Map<String,Boolean> getExtra() { return extra; } 27 } 28 29 static class AnyOnlyBean 30 { 31 @JsonAnyGetter any()32 public Map<String,Integer> any() { 33 HashMap<String,Integer> map = new HashMap<String,Integer>(); 34 map.put("a", 3); 35 return map; 36 } 37 } 38 39 // For [databind#1376]: allow disabling any-getter 40 static class NotEvenAnyBean extends AnyOnlyBean 41 { 42 @JsonAnyGetter(enabled=false) 43 @Override any()44 public Map<String,Integer> any() { 45 throw new RuntimeException("Should not get called!)"); 46 } 47 getValue()48 public int getValue() { return 42; } 49 } 50 51 static class MapAsAny 52 { 53 protected Map<String,Object> stuff = new LinkedHashMap<String,Object>(); 54 55 @JsonAnyGetter any()56 public Map<String,Object> any() { 57 return stuff; 58 } 59 add(String key, Object value)60 public void add(String key, Object value) { 61 stuff.put(key, value); 62 } 63 } 64 65 static class Issue705Bean 66 { 67 protected Map<String,String> stuff; 68 Issue705Bean(String key, String value)69 public Issue705Bean(String key, String value) { 70 stuff = new LinkedHashMap<String,String>(); 71 stuff.put(key, value); 72 } 73 74 @JsonSerialize(using = Issue705Serializer.class) 75 // @JsonSerialize(converter = MyConverter.class) 76 @JsonAnyGetter getParameters()77 public Map<String, String> getParameters(){ 78 return stuff; 79 } 80 } 81 82 @SuppressWarnings("serial") 83 static class Issue705Serializer extends StdSerializer<Object> 84 { Issue705Serializer()85 public Issue705Serializer() { 86 super(Map.class, false); 87 } 88 89 @Override serialize(Object value, JsonGenerator jgen, SerializerProvider provider)90 public void serialize(Object value, JsonGenerator jgen, 91 SerializerProvider provider) throws IOException 92 { 93 StringBuilder sb = new StringBuilder(); 94 for (Map.Entry<?,?> entry : ((Map<?,?>) value).entrySet()) { 95 sb.append('[').append(entry.getKey()).append('/').append(entry.getValue()).append(']'); 96 } 97 jgen.writeStringField("stuff", sb.toString()); 98 } 99 } 100 101 // [databind#1124] 102 static class Bean1124 103 { 104 protected Map<String,String> additionalProperties; 105 addAdditionalProperty(String key, String value)106 public void addAdditionalProperty(String key, String value) { 107 if (additionalProperties == null) { 108 additionalProperties = new HashMap<String,String>(); 109 } 110 additionalProperties.put(key,value); 111 } 112 setAdditionalProperties(Map<String, String> additionalProperties)113 public void setAdditionalProperties(Map<String, String> additionalProperties) { 114 this.additionalProperties = additionalProperties; 115 } 116 117 @JsonAnyGetter 118 @JsonSerialize(contentUsing=MyUCSerializer.class) getAdditionalProperties()119 public Map<String,String> getAdditionalProperties() { return additionalProperties; } 120 } 121 122 // [databind#1124] 123 @SuppressWarnings("serial") 124 static class MyUCSerializer extends StdScalarSerializer<String> 125 { MyUCSerializer()126 public MyUCSerializer() { super(String.class); } 127 128 @Override serialize(String value, JsonGenerator gen, SerializerProvider provider)129 public void serialize(String value, JsonGenerator gen, 130 SerializerProvider provider) throws IOException { 131 gen.writeString(value.toUpperCase()); 132 } 133 } 134 135 static class Bean2592NoAnnotations 136 { 137 protected Map<String, String> properties = new HashMap<>(); 138 139 @JsonAnyGetter getProperties()140 public Map<String, String> getProperties() { 141 return properties; 142 } 143 setProperties(Map<String, String> properties)144 public void setProperties(Map<String, String> properties) { 145 this.properties = properties; 146 } 147 add(String key, String value)148 public void add(String key, String value) { 149 properties.put(key, value); 150 } 151 } 152 153 static class Bean2592PropertyIncludeNonEmpty extends Bean2592NoAnnotations 154 { 155 @JsonInclude(content = JsonInclude.Include.NON_EMPTY) 156 @JsonAnyGetter 157 @Override getProperties()158 public Map<String, String> getProperties() { 159 return properties; 160 } 161 } 162 163 @JsonFilter("Bean2592") 164 static class Bean2592WithFilter extends Bean2592NoAnnotations {} 165 166 /* 167 /********************************************************** 168 /* Test methods 169 /********************************************************** 170 */ 171 172 private final ObjectMapper MAPPER = new ObjectMapper(); 173 testSimpleAnyBean()174 public void testSimpleAnyBean() throws Exception 175 { 176 String json = MAPPER.writeValueAsString(new Bean()); 177 Map<?,?> map = MAPPER.readValue(json, Map.class); 178 assertEquals(2, map.size()); 179 assertEquals(Integer.valueOf(3), map.get("x")); 180 assertEquals(Boolean.TRUE, map.get("a")); 181 } 182 testAnyOnly()183 public void testAnyOnly() throws Exception 184 { 185 ObjectMapper m; 186 187 // First, with normal fail settings: 188 m = new ObjectMapper(); 189 m.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, true); 190 String json = serializeAsString(m, new AnyOnlyBean()); 191 assertEquals("{\"a\":3}", json); 192 193 // then without fail 194 m = new ObjectMapper(); 195 m.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); 196 json = serializeAsString(m, new AnyOnlyBean()); 197 assertEquals("{\"a\":3}", json); 198 } 199 testAnyDisabling()200 public void testAnyDisabling() throws Exception 201 { 202 String json = MAPPER.writeValueAsString(new NotEvenAnyBean()); 203 assertEquals(aposToQuotes("{'value':42}"), json); 204 } 205 206 // Trying to repro [databind#577] testAnyWithNull()207 public void testAnyWithNull() throws Exception 208 { 209 MapAsAny input = new MapAsAny(); 210 input.add("bar", null); 211 assertEquals(aposToQuotes("{'bar':null}"), 212 MAPPER.writeValueAsString(input)); 213 } 214 testIssue705()215 public void testIssue705() throws Exception 216 { 217 Issue705Bean input = new Issue705Bean("key", "value"); 218 String json = MAPPER.writeValueAsString(input); 219 assertEquals("{\"stuff\":\"[key/value]\"}", json); 220 } 221 222 // [databind#1124] testAnyGetterWithValueSerializer()223 public void testAnyGetterWithValueSerializer() throws Exception 224 { 225 ObjectMapper mapper = new ObjectMapper(); 226 Bean1124 input = new Bean1124(); 227 input.addAdditionalProperty("key", "value"); 228 String json = mapper.writeValueAsString(input); 229 assertEquals("{\"key\":\"VALUE\"}", json); 230 } 231 232 // [databind#2592] testAnyGetterWithMapperDefaultIncludeNonEmpty()233 public void testAnyGetterWithMapperDefaultIncludeNonEmpty() throws Exception 234 { 235 ObjectMapper mapper = new ObjectMapper() 236 .setSerializationInclusion(JsonInclude.Include.NON_EMPTY); 237 Bean2592NoAnnotations input = new Bean2592NoAnnotations(); 238 input.add("non-empty", "property"); 239 input.add("empty", ""); 240 input.add("null", null); 241 String json = mapper.writeValueAsString(input); 242 assertEquals("{\"non-empty\":\"property\"}", json); 243 } 244 245 // [databind#2592] testAnyGetterWithMapperDefaultIncludeNonEmptyAndFilterOnBean()246 public void testAnyGetterWithMapperDefaultIncludeNonEmptyAndFilterOnBean() throws Exception 247 { 248 FilterProvider filters = new SimpleFilterProvider() 249 .addFilter("Bean2592", SimpleBeanPropertyFilter.serializeAllExcept("something")); 250 ObjectMapper mapper = new ObjectMapper() 251 .setSerializationInclusion(JsonInclude.Include.NON_EMPTY) 252 .setFilterProvider(filters); 253 Bean2592WithFilter input = new Bean2592WithFilter(); 254 input.add("non-empty", "property"); 255 input.add("empty", ""); 256 input.add("null", null); 257 String json = mapper.writeValueAsString(input); 258 // Unfortunately path for bean with filter is different. It still skips nulls. 259 assertEquals("{\"non-empty\":\"property\",\"empty\":\"\"}", json); 260 } 261 262 // [databind#2592] testAnyGetterWithPropertyIncludeNonEmpty()263 public void testAnyGetterWithPropertyIncludeNonEmpty() throws Exception 264 { 265 ObjectMapper mapper = new ObjectMapper(); 266 Bean2592PropertyIncludeNonEmpty input = new Bean2592PropertyIncludeNonEmpty(); 267 input.add("non-empty", "property"); 268 input.add("empty", ""); 269 input.add("null", null); 270 String json = mapper.writeValueAsString(input); 271 assertEquals("{\"non-empty\":\"property\"}", json); 272 } 273 274 // [databind#2592] testAnyGetterConfigIncludeNonEmpty()275 public void testAnyGetterConfigIncludeNonEmpty() throws Exception 276 { 277 ObjectMapper mapper = new ObjectMapper(); 278 mapper.configOverride(Map.class).setInclude(JsonInclude.Value.construct( 279 JsonInclude.Include.USE_DEFAULTS, 280 JsonInclude.Include.NON_EMPTY 281 )); 282 Bean2592NoAnnotations input = new Bean2592NoAnnotations(); 283 input.add("non-empty", "property"); 284 input.add("empty", ""); 285 input.add("null", null); 286 String json = mapper.writeValueAsString(input); 287 assertEquals("{\"non-empty\":\"property\"}", json); 288 } 289 } 290