1 package com.fasterxml.jackson.databind.jsonschema; 2 3 import java.math.BigDecimal; 4 import java.math.BigInteger; 5 import java.util.Collection; 6 import java.util.Map; 7 8 import com.fasterxml.jackson.annotation.*; 9 import com.fasterxml.jackson.databind.JsonNode; 10 import com.fasterxml.jackson.databind.ObjectMapper; 11 import com.fasterxml.jackson.databind.node.ObjectNode; 12 import com.fasterxml.jackson.databind.ser.FilterProvider; 13 import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; 14 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; 15 16 /** 17 * @author Ryan Heaton 18 */ 19 @SuppressWarnings("deprecation") 20 public class TestGenerateJsonSchema 21 extends com.fasterxml.jackson.databind.BaseMapTest 22 { 23 /* 24 /********************************************************** 25 /* Helper classes 26 /********************************************************** 27 */ 28 29 public static class SimpleBean 30 { 31 private int property1; 32 private String property2; 33 private String[] property3; 34 private Collection<Float> property4; 35 @JsonProperty(required=true) 36 private String property5; 37 getProperty1()38 public int getProperty1() 39 { 40 return property1; 41 } 42 setProperty1(int property1)43 public void setProperty1(int property1) 44 { 45 this.property1 = property1; 46 } 47 getProperty2()48 public String getProperty2() 49 { 50 return property2; 51 } 52 setProperty2(String property2)53 public void setProperty2(String property2) 54 { 55 this.property2 = property2; 56 } 57 getProperty3()58 public String[] getProperty3() 59 { 60 return property3; 61 } 62 setProperty3(String[] property3)63 public void setProperty3(String[] property3) 64 { 65 this.property3 = property3; 66 } 67 getProperty4()68 public Collection<Float> getProperty4() 69 { 70 return property4; 71 } 72 setProperty4(Collection<Float> property4)73 public void setProperty4(Collection<Float> property4) 74 { 75 this.property4 = property4; 76 } 77 getProperty5()78 public String getProperty5() 79 { 80 return property5; 81 } 82 setProperty5(String property5)83 public void setProperty5(String property5) 84 { 85 this.property5 = property5; 86 } 87 } 88 89 public class TrivialBean { 90 public String name; 91 } 92 93 @JsonSerializableSchema(id="myType") 94 public class BeanWithId { 95 public String value; 96 } 97 98 static class UnwrappingRoot 99 { 100 public int age; 101 102 @JsonUnwrapped(prefix="name.") 103 public Name name; 104 } 105 106 static class Name { 107 public String first, last; 108 } 109 110 @JsonPropertyOrder({ "dec", "bigInt" }) 111 static class Numbers { 112 public BigDecimal dec; 113 public BigInteger bigInt; 114 } 115 116 /* 117 /********************************************************** 118 /* Unit tests 119 /********************************************************** 120 */ 121 122 private final ObjectMapper MAPPER = new ObjectMapper(); 123 124 /** 125 * tests generating json-schema stuff. 126 */ testOldSchemaGeneration()127 public void testOldSchemaGeneration() throws Exception 128 { 129 JsonSchema jsonSchema = MAPPER.generateJsonSchema(SimpleBean.class); 130 131 assertNotNull(jsonSchema); 132 133 // test basic equality, and that equals() handles null, other obs 134 assertTrue(jsonSchema.equals(jsonSchema)); 135 assertFalse(jsonSchema.equals(null)); 136 assertFalse(jsonSchema.equals("foo")); 137 138 // other basic things 139 assertNotNull(jsonSchema.toString()); 140 assertNotNull(JsonSchema.getDefaultSchemaNode()); 141 142 ObjectNode root = jsonSchema.getSchemaNode(); 143 assertEquals("object", root.get("type").asText()); 144 assertEquals(false, root.path("required").booleanValue()); 145 JsonNode propertiesSchema = root.get("properties"); 146 assertNotNull(propertiesSchema); 147 JsonNode property1Schema = propertiesSchema.get("property1"); 148 assertNotNull(property1Schema); 149 assertEquals("integer", property1Schema.get("type").asText()); 150 assertEquals(false, property1Schema.path("required").booleanValue()); 151 JsonNode property2Schema = propertiesSchema.get("property2"); 152 assertNotNull(property2Schema); 153 assertEquals("string", property2Schema.get("type").asText()); 154 assertEquals(false, property2Schema.path("required").booleanValue()); 155 JsonNode property3Schema = propertiesSchema.get("property3"); 156 assertNotNull(property3Schema); 157 assertEquals("array", property3Schema.get("type").asText()); 158 assertEquals(false, property3Schema.path("required").booleanValue()); 159 assertEquals("string", property3Schema.get("items").get("type").asText()); 160 JsonNode property4Schema = propertiesSchema.get("property4"); 161 assertNotNull(property4Schema); 162 assertEquals("array", property4Schema.get("type").asText()); 163 assertEquals(false, property4Schema.path("required").booleanValue()); 164 assertEquals("number", property4Schema.get("items").get("type").asText()); 165 } 166 167 @JsonFilter("filteredBean") 168 protected static class FilteredBean { 169 170 @JsonProperty 171 private String secret = "secret"; 172 173 @JsonProperty 174 private String obvious = "obvious"; 175 getSecret()176 public String getSecret() { return secret; } setSecret(String s)177 public void setSecret(String s) { secret = s; } 178 getObvious()179 public String getObvious() { return obvious; } setObvious(String s)180 public void setObvious(String s) {obvious = s; } 181 } 182 183 final static FilterProvider secretFilterProvider = new SimpleFilterProvider() 184 .addFilter("filteredBean", SimpleBeanPropertyFilter.filterOutAllExcept(new String[]{"obvious"})); 185 testGeneratingJsonSchemaWithFilters()186 public void testGeneratingJsonSchemaWithFilters() throws Exception { 187 ObjectMapper mapper = new ObjectMapper(); 188 mapper.setFilters(secretFilterProvider); 189 JsonSchema schema = mapper.generateJsonSchema(FilteredBean.class); 190 JsonNode node = schema.getSchemaNode().get("properties"); 191 assertTrue(node.has("obvious")); 192 assertFalse(node.has("secret")); 193 } 194 195 /** 196 * Additional unit test for verifying that schema object itself 197 * can be properly serialized 198 */ testSchemaSerialization()199 public void testSchemaSerialization() throws Exception 200 { 201 JsonSchema jsonSchema = MAPPER.generateJsonSchema(SimpleBean.class); 202 Map<String,Object> result = writeAndMap(MAPPER, jsonSchema); 203 assertNotNull(result); 204 // no need to check out full structure, just basics... 205 assertEquals("object", result.get("type")); 206 // only add 'required' if it is true... 207 assertNull(result.get("required")); 208 assertNotNull(result.get("properties")); 209 } 210 testThatObjectsHaveNoItems()211 public void testThatObjectsHaveNoItems() throws Exception 212 { 213 JsonSchema jsonSchema = MAPPER.generateJsonSchema(TrivialBean.class); 214 String json = jsonSchema.toString().replaceAll("\"", "'"); 215 // can we count on ordering being stable? I think this is true with current ObjectNode impl 216 // as perh [JACKSON-563]; 'required' is only included if true 217 assertEquals("{'type':'object','properties':{'name':{'type':'string'}}}", 218 json); 219 } 220 testSchemaId()221 public void testSchemaId() throws Exception 222 { 223 JsonSchema jsonSchema = MAPPER.generateJsonSchema(BeanWithId.class); 224 String json = jsonSchema.toString().replaceAll("\"", "'"); 225 assertEquals("{'type':'object','id':'myType','properties':{'value':{'type':'string'}}}", 226 json); 227 } 228 229 // [databind#271] testUnwrapping()230 public void testUnwrapping() throws Exception 231 { 232 JsonSchema jsonSchema = MAPPER.generateJsonSchema(UnwrappingRoot.class); 233 String json = jsonSchema.toString().replaceAll("\"", "'"); 234 String EXP = "{'type':'object'," 235 +"'properties':{'age':{'type':'integer'}," 236 +"'name.first':{'type':'string'},'name.last':{'type':'string'}}}"; 237 assertEquals(EXP, json); 238 } 239 240 // testNumberTypes()241 public void testNumberTypes() throws Exception 242 { 243 JsonSchema jsonSchema = MAPPER.generateJsonSchema(Numbers.class); 244 String json = quotesToApos(jsonSchema.toString()); 245 String EXP = "{'type':'object'," 246 +"'properties':{'dec':{'type':'number'}," 247 +"'bigInt':{'type':'integer'}}}"; 248 assertEquals(EXP, json); 249 } 250 } 251