Jackson2的JsonSchema实现java实体类生成json方式

目录

  • 核心工具类
  • 怎么使用
    • 测试用的实体类
  • 用法
    • 转换结果
      除Swagger等文档插件,全网首发,同时支持Json和Xml
      【Jackson2的JsonSchema实现java实体类生成json方式】
      核心工具类 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 () {@Overridepublic void serialize(Object value, JsonGenerator gen, SerializerProvider serializers)throws IOException {gen.writeString(""); }}); } /*** 普通java类转json字符串* @param * @param mapper* @param clazz* @return*/ public static String clazz2Json(ObjectMapper mapper, Class clazz) {JavaType javaType = mapper.getTypeFactory().constructType(clazz); return javaType2Json(mapper, javaType); } /*** 泛型java类转json字符串* @param * @param mapper* @param reference* @return*/ public static String clazz2Json(ObjectMapper mapper, TypeReference 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 = https://www.it610.com/article/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 iterator = source.get("properties").fields(); while (iterator.hasNext()) {Map.Entry 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 { 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 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 getTestStr() {return testStr; } public void setTestStr(List 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 mapList; public List getMapList() {return mapList; } public void setMapList(List 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 extends Base { private String userName; private Integer age; private String phone; private LocalDateTime accessTime; private LocalTime localTime; private Score score; private List grades; private Map mapLt; private Map mapStr; private Map mapLocal; private List lscoreList1; private List> lscoreList2; private Map>> mapScore; private Map> 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 getGrades() {return grades; } public void setGrades(List grades) {this.grades = grades; } public Map getMapLt() {return mapLt; } public void setMapLt(Map mapLt) {this.mapLt = mapLt; } public Map getMapStr() {return mapStr; } public void setMapStr(Map mapStr) {this.mapStr = mapStr; } public Map getMapLocal() {return mapLocal; } public void setMapLocal(Map 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 getLscoreList1() {return lscoreList1; } public void setLscoreList1(List lscoreList1) {this.lscoreList1 = lscoreList1; } public List> getLscoreList2() {return lscoreList2; } public void setLscoreList2(List> lscoreList2) {this.lscoreList2 = lscoreList2; } public Map>> getMapScore() {return mapScore; } public void setMapScore(Map>> mapScore) {this.mapScore = mapScore; } public Map> getMapList() {return mapList; } public void setMapList(Map> 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>>() {}); System.out.println(json); ObjectMapper mapper2 = XmlUtils.getObjectMapper(); String xml = Json2Utils.clazz2Json(mapper2, new TypeReference>() {}); 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
      } ]
      } ] ]
      0false0.00.0

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

        推荐阅读