package com.fasterxml.jackson.databind.jsonschema; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.Map; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.ser.FilterProvider; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; /** * @author Ryan Heaton */ @SuppressWarnings("deprecation") public class TestGenerateJsonSchema extends com.fasterxml.jackson.databind.BaseMapTest { /* /********************************************************** /* Helper classes /********************************************************** */ public static class SimpleBean { private int property1; private String property2; private String[] property3; private Collection<Float> property4; @JsonProperty(required=true) private String property5; public int getProperty1() { return property1; } public void setProperty1(int property1) { this.property1 = property1; } public String getProperty2() { return property2; } public void setProperty2(String property2) { this.property2 = property2; } public String[] getProperty3() { return property3; } public void setProperty3(String[] property3) { this.property3 = property3; } public Collection<Float> getProperty4() { return property4; } public void setProperty4(Collection<Float> property4) { this.property4 = property4; } public String getProperty5() { return property5; } public void setProperty5(String property5) { this.property5 = property5; } } public class TrivialBean { public String name; } @JsonSerializableSchema(id="myType") public class BeanWithId { public String value; } static class UnwrappingRoot { public int age; @JsonUnwrapped(prefix="name.") public Name name; } static class Name { public String first, last; } @JsonPropertyOrder({ "dec", "bigInt" }) static class Numbers { public BigDecimal dec; public BigInteger bigInt; } /* /********************************************************** /* Unit tests /********************************************************** */ private final ObjectMapper MAPPER = new ObjectMapper(); /** * tests generating json-schema stuff. */ public void testOldSchemaGeneration() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(SimpleBean.class); assertNotNull(jsonSchema); // test basic equality, and that equals() handles null, other obs assertTrue(jsonSchema.equals(jsonSchema)); assertFalse(jsonSchema.equals(null)); assertFalse(jsonSchema.equals("foo")); // other basic things assertNotNull(jsonSchema.toString()); assertNotNull(JsonSchema.getDefaultSchemaNode()); ObjectNode root = jsonSchema.getSchemaNode(); assertEquals("object", root.get("type").asText()); assertEquals(false, root.path("required").booleanValue()); JsonNode propertiesSchema = root.get("properties"); assertNotNull(propertiesSchema); JsonNode property1Schema = propertiesSchema.get("property1"); assertNotNull(property1Schema); assertEquals("integer", property1Schema.get("type").asText()); assertEquals(false, property1Schema.path("required").booleanValue()); JsonNode property2Schema = propertiesSchema.get("property2"); assertNotNull(property2Schema); assertEquals("string", property2Schema.get("type").asText()); assertEquals(false, property2Schema.path("required").booleanValue()); JsonNode property3Schema = propertiesSchema.get("property3"); assertNotNull(property3Schema); assertEquals("array", property3Schema.get("type").asText()); assertEquals(false, property3Schema.path("required").booleanValue()); assertEquals("string", property3Schema.get("items").get("type").asText()); JsonNode property4Schema = propertiesSchema.get("property4"); assertNotNull(property4Schema); assertEquals("array", property4Schema.get("type").asText()); assertEquals(false, property4Schema.path("required").booleanValue()); assertEquals("number", property4Schema.get("items").get("type").asText()); } @JsonFilter("filteredBean") protected static class FilteredBean { @JsonProperty private String secret = "secret"; @JsonProperty private String obvious = "obvious"; public String getSecret() { return secret; } public void setSecret(String s) { secret = s; } public String getObvious() { return obvious; } public void setObvious(String s) {obvious = s; } } final static FilterProvider secretFilterProvider = new SimpleFilterProvider() .addFilter("filteredBean", SimpleBeanPropertyFilter.filterOutAllExcept(new String[]{"obvious"})); public void testGeneratingJsonSchemaWithFilters() throws Exception { ObjectMapper mapper = new ObjectMapper(); mapper.setFilters(secretFilterProvider); JsonSchema schema = mapper.generateJsonSchema(FilteredBean.class); JsonNode node = schema.getSchemaNode().get("properties"); assertTrue(node.has("obvious")); assertFalse(node.has("secret")); } /** * Additional unit test for verifying that schema object itself * can be properly serialized */ public void testSchemaSerialization() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(SimpleBean.class); Map<String,Object> result = writeAndMap(MAPPER, jsonSchema); assertNotNull(result); // no need to check out full structure, just basics... assertEquals("object", result.get("type")); // only add 'required' if it is true... assertNull(result.get("required")); assertNotNull(result.get("properties")); } public void testThatObjectsHaveNoItems() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(TrivialBean.class); String json = jsonSchema.toString().replaceAll("\"", "'"); // can we count on ordering being stable? I think this is true with current ObjectNode impl // as perh [JACKSON-563]; 'required' is only included if true assertEquals("{'type':'object','properties':{'name':{'type':'string'}}}", json); } public void testSchemaId() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(BeanWithId.class); String json = jsonSchema.toString().replaceAll("\"", "'"); assertEquals("{'type':'object','id':'myType','properties':{'value':{'type':'string'}}}", json); } // [databind#271] public void testUnwrapping() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(UnwrappingRoot.class); String json = jsonSchema.toString().replaceAll("\"", "'"); String EXP = "{'type':'object'," +"'properties':{'age':{'type':'integer'}," +"'name.first':{'type':'string'},'name.last':{'type':'string'}}}"; assertEquals(EXP, json); } // public void testNumberTypes() throws Exception { JsonSchema jsonSchema = MAPPER.generateJsonSchema(Numbers.class); String json = quotesToApos(jsonSchema.toString()); String EXP = "{'type':'object'," +"'properties':{'dec':{'type':'number'}," +"'bigInt':{'type':'integer'}}}"; assertEquals(EXP, json); } }