Jackson2的JsonSchema实现java实体类生成json方式
目录
- 核心工具类
- 怎么使用
- 测试用的实体类
- 用法
- 转换结果
除Swagger等文档插件,全网首发,同时支持Json和Xml
核心工具类
Json2Utils.java
package com.xxx.demo.common.util; import java.io.IOException; import java.util.Arrays; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.NullNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.dataformat.xml.XmlMapper; import com.fasterxml.jackson.dataformat.xml.ser.XmlSerializerProvider; import com.fasterxml.jackson.dataformat.xml.util.XmlRootNameLookup; import com.kjetland.jackson.jsonSchema.JsonSchemaConfig; import com.kjetland.jackson.jsonSchema.JsonSchemaGenerator; public final class Json2Utils { //数组或List的循环次数 private static final int ARRAY_LOOP = 1; //Map的循环次数 private static final int MAP_LOOP = 1; //Map的key的前缀 private static final String MAP_KEY_PREFIX = "KEY_"; private static final ObjectMapper innerMapper = new ObjectMapper(); private static final XmlSerializerProvider provider = new XmlSerializerProvider(new XmlRootNameLookup()); static { provider.setNullValueSerializer(new JsonSerializer<Object> () { @Override public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { gen.writeString(""); } }); } /** * 普通java类转json字符串 * @param <T> * @param mapper * @param clazz * @return */ public static <T> String clazz2Json(ObjectMapper mapper, Class<T> clazz) { JavaType javaType = mapper.getTypeFactory().constructType(clazz); return javaType2Json(mapper, javaType); } /** * 泛型java类转json字符串 * @param <T> * @param mapper * @param reference * @return */ public static <T> String clazz2Json(ObjectMapper mapper, TypeReference<T> reference) { JavaType javaType = mapper.getTypeFactory().constructType(reference); return javaType2Json(mapper, javaType); } private static String javaType2Json(ObjectMapper mapperSource, JavaType javaType) { ObjectMapper mapper = mapperSource.copy(); ObjectMapper innerMapper = Json2Utils.innerMapper; JsonSchemaConfig config = JsonSchemaConfig.vanillaJsonSchemaDraft4(); JsonSchemaGenerator schemaGenerator = new JsonSchemaGenerator(innerMapper, config); JsonNode jsonNode = schemaGenerator.generateJsonSchema(javaType); JsonNode normalize = normalize(innerMapper, jsonNode); Object value = innerMapper.convertValue(normalize, javaType); mapper.setDefaultPropertyInclusion(Include.ALWAYS); if (mapper instanceof XmlMapper) { mapper.setSerializerProvider(provider); } try { return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value); } catch (JsonProcessingException e) { return null; } } private static JsonNode normalize(ObjectMapper mapper, JsonNode source) { if (shouldArray(source)) { ArrayNode arrayNode = mapper.createArrayNode(); fillJsonNode(mapper, source, source, arrayNode); return arrayNode; } else if (shouldObject(source)) { ObjectNode objectNode = mapper.createObjectNode(); fillJsonNode(mapper, source, source, objectNode); return objectNode; } return NullNode.getInstance(); } private static void fillJsonNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target) { if (isArray(source)) { for (int i = 0; i < ARRAY_LOOP; i++) { fillArrayNode(mapper, sourceRoot, source, target); } } else if (shouldObject(source)) { fillObjectNode(mapper, sourceRoot, source, target); } } private static void fillArrayNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target) { JsonNode arrayItems = getArrayItems(source); if (isArray(arrayItems)) { ArrayNode arrayNode = mapper.createArrayNode(); ((ArrayNode) target).add(arrayNode); fillJsonNode(mapper, sourceRoot, arrayItems, arrayNode); } else if (isMap(arrayItems)) { JsonNode propertiesNode = arrayItems.get("additionalProperties"); if (isPojoPlain(propertiesNode)) { ObjectNode objectNode = mapper.createObjectNode(); ((ArrayNode) target).add(objectNode); fillJsonNode(mapper, sourceRoot, arrayItems, objectNode); } else { ((ArrayNode) target).add(NullNode.getInstance()); } } else if (isPojoPlain(arrayItems)) { JsonNode jsonNode = sourceRoot.at(arrayItems.get("$ref").asText().substring(1)); ObjectNode objectNode = mapper.createObjectNode(); ((ArrayNode) target).add(objectNode); fillJsonNode(mapper, sourceRoot, jsonNode, objectNode); } else { ((ArrayNode) target).add(NullNode.getInstance()); } } private static void fillObjectNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target) { if (isMap(source)) { for (int i = 0; i < MAP_LOOP; i++) { fillMapNode(mapper, sourceRoot, source, target, i); } } else if (source.has("properties")) { Iterator<Entry<String, JsonNode>> iterator = source.get("properties").fields(); while (iterator.hasNext()) { Map.Entry<String, JsonNode> entry = iterator.next(); JsonNode jsonNode = entry.getValue(); if (shouldArray(jsonNode)) { ArrayNode arrayNode = mapper.createArrayNode(); ((ObjectNode) target).set(entry.getKey(), arrayNode); fillJsonNode(mapper, sourceRoot, jsonNode, arrayNode); } else if (shouldObject(jsonNode)) { ObjectNode objectNode = mapper.createObjectNode(); ((ObjectNode) target).set(entry.getKey(), objectNode); fillJsonNode(mapper, sourceRoot, jsonNode, objectNode); } else { ((ObjectNode) target).set(entry.getKey(), NullNode.getInstance()); } } } } private static void fillMapNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target, int i) { String keyName = MAP_KEY_PREFIX + i; JsonNode propertiesNode = source.get("additionalProperties"); if (isArray(propertiesNode)) { ArrayNode arrayNode = mapper.createArrayNode(); ((ObjectNode) target).set(keyName, arrayNode); fillJsonNode(mapper, sourceRoot, propertiesNode, arrayNode); } else if (isMap(propertiesNode)) { ObjectNode objectNode = mapper.createObjectNode(); ((ObjectNode) target).set(keyName, objectNode); fillJsonNode(mapper, sourceRoot, propertiesNode, objectNode); } else if (isPojoPlain(propertiesNode)) { JsonNode jsonNode = sourceRoot.at(propertiesNode.get("$ref").asText().substring(1)); ObjectNode objectNode = mapper.createObjectNode(); ((ObjectNode) target).set(keyName, objectNode); fillJsonNode(mapper, sourceRoot, jsonNode, objectNode); } else { ((ObjectNode) target).set(keyName, NullNode.getInstance()); } } private static boolean isArray(JsonNode jsonNode) { if (!jsonNode.has("type")) { return false; } return "array".equals(jsonNode.get("type").asText()); } private static boolean isMap(JsonNode jsonNode) { if (!jsonNode.has("type")) { return false; } return "object".equals(jsonNode.get("type").asText()) && !jsonNode.get("additionalProperties").isBoolean(); } private static boolean isPojoRoot(JsonNode jsonNode) { return "object".equals(jsonNode.get("type").asText()) && jsonNode.get("additionalProperties").isBoolean() && !Arrays.asList("Local Date Time", "Local Date", "Local Time", "Offset Date Time").contains(jsonNode.get("title").asText()); } private static boolean isPojoPlain(JsonNode jsonNode) { if (jsonNode.has("properties")) { return true; } if (!jsonNode.has("$ref")) { return false; } String ref = jsonNode.get("$ref").asText(); return !ref.endsWith("LocalDateTime") && !ref.endsWith("LocalDate") && !ref.endsWith("LocalTime") && !ref.endsWith("OffsetDateTime"); } private static boolean shouldArray(JsonNode jsonNode) { return isArray(jsonNode); } private static boolean shouldObject(JsonNode jsonNode) { if (isMap(jsonNode)) { return true; } if (jsonNode.has("title") && isPojoRoot(jsonNode)) { return true; } if (!jsonNode.has("title") && isPojoPlain(jsonNode)) { return true; } return false; } private static JsonNode getArrayItems(JsonNode source) { return source.get("items"); } }
怎么使用
测试用的实体类
Base.java
package com.xxx.demo.common.jsontest; import java.util.Arrays; public class Base<T> { private String address; private T[] listDt; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public T[] getListDt() { return listDt; } public void setListDt(T[] listDt) { this.listDt = listDt; } @Override public String toString() { return "Base [address=" + address + ", listDt=" + Arrays.toString(listDt) + "]"; } }
BaseDt.java
package com.xxx.demo.common.jsontest; import java.math.BigInteger; import java.time.LocalDate; import java.util.Date; import java.util.List; public class BaseDt { private Integer bst; private Date dt; private BigInteger bg; private int nt; private Short sht; private Long lng; private Byte bt; @JacksonXmlCData private char chr; private boolean bln; private float flt; private double dbl; private LocalDate ld; private List<String> testStr; private Score score; public Integer getBst() { return bst; } public void setBst(Integer bst) { this.bst = bst; } public Date getDt() { return dt; } public void setDt(Date dt) { this.dt = dt; } public BigInteger getBg() { return bg; } public void setBg(BigInteger bg) { this.bg = bg; } public int getNt() { return nt; } public void setNt(int nt) { this.nt = nt; } public Short getSht() { return sht; } public void setSht(Short sht) { this.sht = sht; } public Long getLng() { return lng; } public void setLng(Long lng) { this.lng = lng; } public Byte getBt() { return bt; } public void setBt(Byte bt) { this.bt = bt; } public char getChr() { return chr; } public void setChr(char chr) { this.chr = chr; } public boolean isBln() { return bln; } public void setBln(boolean bln) { this.bln = bln; } public float getFlt() { return flt; } public void setFlt(float flt) { this.flt = flt; } public double getDbl() { return dbl; } public void setDbl(double dbl) { this.dbl = dbl; } public LocalDate getLd() { return ld; } public void setLd(LocalDate ld) { this.ld = ld; } public List<String> getTestStr() { return testStr; } public void setTestStr(List<String> testStr) { this.testStr = testStr; } public Score getScore() { return score; } public void setScore(Score score) { this.score = score; } @Override public String toString() { return "BaseDt [bst=" + bst + ", dt=" + dt + ", bg=" + bg + ", nt=" + nt + ", sht=" + sht + ", lng=" + lng + ", bt=" + bt + ", chr=" + chr + ", bln=" + bln + ", flt=" + flt + ", dbl=" + dbl + ", ld=" + ld + ", testStr=" + testStr + ", score=" + score + "]"; } }
Score.java
package com.xxx.demo.common.jsontest; import java.math.BigDecimal; public class Score { private BigDecimal langue; private BigDecimal math; private BigDecimal english; public BigDecimal getLangue() { return langue; } public void setLangue(BigDecimal langue) { this.langue = langue; } public BigDecimal getMath() { return math; } public void setMath(BigDecimal math) { this.math = math; } public BigDecimal getEnglish() { return english; } public void setEnglish(BigDecimal english) { this.english = english; } @Override public String toString() { return "Score [langue=" + langue + ", math=" + math + ", english=" + english + "]"; } }
TestMap.java
package com.xxx.demo.common.jsontest; import java.util.List; public class TestMap { private List<String> mapList; public List<String> getMapList() { return mapList; } public void setMapList(List<String> mapList) { this.mapList = mapList; } @Override public String toString() { return "TestMap [mapList=" + mapList + "]"; } }
Student.java
package com.xxx.demo.common.jsontest; import java.time.LocalDateTime; import java.time.LocalTime; import java.util.List; import java.util.Map; public class Student<T, E> extends Base<BaseDt> { private String userName; private Integer age; private String phone; private LocalDateTime accessTime; private LocalTime localTime; private Score score; private List<T> grades; private Map<String, E> mapLt; private Map<String, String> mapStr; private Map<String, LocalDateTime> mapLocal; private List<Map<String, Score>> lscoreList1; private List<List<Map<String, Score>>> lscoreList2; private Map<String, Map<String, Map<String, Score>>> mapScore; private Map<String, List<Score>> mapList; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public LocalDateTime getAccessTime() { return accessTime; } public void setAccessTime(LocalDateTime accessTime) { this.accessTime = accessTime; } public List<T> getGrades() { return grades; } public void setGrades(List<T> grades) { this.grades = grades; } public Map<String, E> getMapLt() { return mapLt; } public void setMapLt(Map<String, E> mapLt) { this.mapLt = mapLt; } public Map<String, String> getMapStr() { return mapStr; } public void setMapStr(Map<String, String> mapStr) { this.mapStr = mapStr; } public Map<String, LocalDateTime> getMapLocal() { return mapLocal; } public void setMapLocal(Map<String, LocalDateTime> mapLocal) { this.mapLocal = mapLocal; } public LocalTime getLocalTime() { return localTime; } public void setLocalTime(LocalTime localTime) { this.localTime = localTime; } public Score getScore() { return score; } public void setScore(Score score) { this.score = score; } public List<Map<String, Score>> getLscoreList1() { return lscoreList1; } public void setLscoreList1(List<Map<String, Score>> lscoreList1) { this.lscoreList1 = lscoreList1; } public List<List<Map<String, Score>>> getLscoreList2() { return lscoreList2; } public void setLscoreList2(List<List<Map<String, Score>>> lscoreList2) { this.lscoreList2 = lscoreList2; } public Map<String, Map<String, Map<String, Score>>> getMapScore() { return mapScore; } public void setMapScore(Map<String, Map<String, Map<String, Score>>> mapScore) { this.mapScore = mapScore; } public Map<String, List<Score>> getMapList() { return mapList; } public void setMapList(Map<String, List<Score>> mapList) { this.mapList = mapList; } @Override public String toString() { return "Student [userName=" + userName + ", age=" + age + ", phone=" + phone + ", accessTime=" + accessTime + ", localTime=" + localTime + ", score=" + score + ", grades=" + grades + ", mapLt=" + mapLt + ", mapStr=" + mapStr + ", mapLocal=" + mapLocal + ", lscoreList1=" + lscoreList1 + ", lscoreList2=" + lscoreList2 + ", mapScore=" + mapScore + ", mapList=" + mapList + "]"; } }
用法
JsonUtils类转Springboot2以代码的方式统一配置Jackson->Jackson工具类
package com.xxx.demo.common.jsontest; import java.util.List; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.xxx.demo.common.util.Json2Utils; import com.xxx.demo.common.util.JsonUtils; import com.xxx.demo.common.util.XmlUtils; public class Json2Test { public static void main(String[] args) { ObjectMapper mapper1 = JsonUtils.getObjectMapper(); String json = Json2Utils.clazz2Json(mapper1, new TypeReference<List<List<Student<Score, TestMap>>>>() {}); System.out.println(json); ObjectMapper mapper2 = XmlUtils.getObjectMapper(); String xml = Json2Utils.clazz2Json(mapper2, new TypeReference<Student<Score, TestMap>>() {}); System.out.println(xml); } }
转换结果
[ [ {
"address" : null,
"listDt" : [ {
"bst" : null,
"dt" : null,
"bg" : null,
"nt" : 0,
"sht" : null,
"lng" : null,
"bt" : null,
"chr" : "\u0000",
"bln" : false,
"flt" : 0.0,
"dbl" : 0.0,
"ld" : null,
"testStr" : [ null ],
"score" : {
"langue" : null,
"math" : null,
"english" : null
}
} ],
"userName" : null,
"age" : null,
"phone" : null,
"accessTime" : null,
"localTime" : null,
"score" : {
"langue" : null,
"math" : null,
"english" : null
},
"mapLt" : {
"KEY_0" : {
"mapList" : [ null ]
}
},
"mapStr" : {
"KEY_0" : null
},
"mapLocal" : {
"KEY_0" : null
},
"lscoreList1" : [ {
"KEY_0" : {
"langue" : null,
"math" : null,
"english" : null
}
} ],
"lscoreList2" : [ [ {
"KEY_0" : {
"langue" : null,
"math" : null,
"english" : null
}
} ] ],
"mapScore" : {
"KEY_0" : {
"KEY_0" : {
"KEY_0" : {
"langue" : null,
"math" : null,
"english" : null
}
}
}
},
"mapList" : {
"KEY_0" : [ {
"langue" : null,
"math" : null,
"english" : null
} ]
},
"gg" : [ {
"langue" : null,
"math" : null,
"english" : null
} ]
} ] ]
<Student> <address></address> <listDt> <listDt> <bst></bst> <dt></dt> <bg></bg> <nt>0</nt> <sht></sht> <lng></lng> <bt></bt> <chr><![CDATA[ ]]></chr> <bln>false</bln> <flt>0.0</flt> <dbl>0.0</dbl> <ld></ld> <testStr> <testStr></testStr> </testStr> <score> <langue></langue> <math></math> <english></english> </score> </listDt> </listDt> <userName></userName> <age></age> <phone></phone> <accessTime></accessTime> <localTime></localTime> <score> <langue></langue> <math></math> <english></english> </score> <mapLt> <KEY_0> <mapList> <mapList></mapList> </mapList> </KEY_0> </mapLt> <mapStr> <KEY_0></KEY_0> </mapStr> <mapLocal> <KEY_0></KEY_0> </mapLocal> <lscoreList1> <lscoreList1> <KEY_0> <langue></langue> <math></math> <english></english> </KEY_0> </lscoreList1> </lscoreList1> <lscoreList2> <lscoreList2> <KEY_0> <langue></langue> <math></math> <english></english> </KEY_0> </lscoreList2> </lscoreList2> <mapScore> <KEY_0> <KEY_0> <KEY_0> <langue></langue> <math></math> <english></english> </KEY_0> </KEY_0> </KEY_0> </mapScore> <mapList> <KEY_0> <langue></langue> <math></math> <english></english> </KEY_0> </mapList> <gg> <gg> <langue></langue> <math></math> <english></english> </gg> </gg> </Student>
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。