当前位置: 首页 > 工具软件 > jsonschema > 使用案例 >

基于Jackson2的JsonSchema实现java实体类生成json(二)

邹英悟
2023-12-01


同时支持Json和Xml

额外的POM依赖

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.module</groupId>
    <artifactId>jackson-module-jsonSchema</artifactId>
</dependency>

核心工具类

Json2Utils.java

package com.xxx.demo.common.util;

import java.io.IOException;
import java.util.HashMap;
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.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.JsonSchemaGenerator;

public 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);
	}

	/**
	 * java类转json字符串
	 * @param mapperSource
	 * @param javaType
	 * @return
	 */
	public static String javaType2Json(ObjectMapper mapperSource, JavaType javaType) {
		try {
			ObjectMapper mapper = mapperSource.copy();
			ObjectMapper innerMapper = Json2Utils.innerMapper;
			
			JsonSchemaGenerator generator = new JsonSchemaGenerator(innerMapper);
			JsonSchema schema = generator.generateSchema(javaType);
			JsonNode jsonNode = innerMapper.valueToTree(schema);
			JsonNode normalize = normalize(innerMapper, jsonNode);
			Object value = innerMapper.convertValue(normalize, javaType);
			mapper.setDefaultPropertyInclusion(Include.ALWAYS);
			if (mapper instanceof XmlMapper) {
				mapper.setSerializerProvider(provider);
			}
			return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(value);
		} catch (JsonProcessingException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	private static JsonNode normalize(ObjectMapper mapper, JsonNode source) {
		System.out.println(source);
		Map<String, JsonNode> refMap = new HashMap<>();
		if (hasId(source)) {
			refMap.put(getId(source), source);
		}
		if (shouldArray(source)) {
			ArrayNode arrayNode = mapper.createArrayNode();
			fillJsonNode(mapper, source, source, arrayNode, refMap);
			return arrayNode;
		} else if (shouldObject(source)) {
			ObjectNode objectNode = mapper.createObjectNode();
			fillJsonNode(mapper, source, source, objectNode, refMap);
			return objectNode;
		}
		return NullNode.getInstance();
		
	}
	
	private static void fillJsonNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target, Map<String, JsonNode> refMap) {
		if (isArray(source)) {
			for (int i = 0; i < ARRAY_LOOP; i++) {
				fillArrayNode(mapper, sourceRoot, source, target, refMap);
			}
		} else if (shouldObject(source)) {
			fillObjectNode(mapper, sourceRoot, source, target, refMap);
		}
	}

	private static void fillArrayNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target, Map<String, JsonNode> refMap) {
		JsonNode arrayItems = getArrayItems(source);
		if (hasId(arrayItems)) {
			refMap.put(getId(arrayItems), arrayItems);
		}
		if (isArray(arrayItems)) {
			ArrayNode arrayNode = mapper.createArrayNode();
			((ArrayNode) target).add(arrayNode);
			fillJsonNode(mapper, sourceRoot, arrayItems, arrayNode, refMap);
		} else if (isMap(arrayItems)) {
			JsonNode propertiesNode = arrayItems.get("additionalProperties");
			if (hasId(propertiesNode)) {
				refMap.put(getId(propertiesNode), propertiesNode);
			}
			if (isPojoPlain(propertiesNode)) {
				ObjectNode objectNode = mapper.createObjectNode();
				((ArrayNode) target).add(objectNode);
				fillJsonNode(mapper, sourceRoot, arrayItems, objectNode, refMap);
			} else {
				((ArrayNode) target).add(NullNode.getInstance());
			}
		} else if (isPojoPlain(arrayItems)) {
			JsonNode jsonNode;
			if (hasProperties(arrayItems)) {
				jsonNode = arrayItems;
			} else {
				jsonNode = refMap.get(getRef(arrayItems));
			}
			ObjectNode objectNode = mapper.createObjectNode();
			((ArrayNode) target).add(objectNode);
			fillJsonNode(mapper, sourceRoot, jsonNode, objectNode, refMap);
		} else {
			((ArrayNode) target).add(NullNode.getInstance());
		}
	}

	private static void fillObjectNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target, Map<String, JsonNode> refMap) {
		if (isMap(source)) {
			for (int i = 0; i < MAP_LOOP; i++) {
				fillMapNode(mapper, sourceRoot, source, target, i, refMap);
			}
		} else if (hasProperties(source)) {
			Iterator<Entry<String, JsonNode>> iterator = getProperties(source).fields();
			while (iterator.hasNext()) {
				Map.Entry<String, JsonNode> entry = iterator.next();
				JsonNode jsonNode = entry.getValue();
				if (hasId(jsonNode)) {
					refMap.put(getId(jsonNode), jsonNode);
				}
				if (shouldArray(jsonNode)) {
					ArrayNode arrayNode = mapper.createArrayNode();
					((ObjectNode) target).set(entry.getKey(), arrayNode);
					fillJsonNode(mapper, sourceRoot, jsonNode, arrayNode, refMap);
				} else if (shouldObject(jsonNode)) {
					ObjectNode objectNode = mapper.createObjectNode();
					((ObjectNode) target).set(entry.getKey(), objectNode);
					fillJsonNode(mapper, sourceRoot, jsonNode, objectNode, refMap);
				} else {
					((ObjectNode) target).set(entry.getKey(), NullNode.getInstance());
				}
				
			}
		}
	}
	
	private static void fillMapNode(ObjectMapper mapper, JsonNode sourceRoot, JsonNode source, JsonNode target, int i, Map<String, JsonNode> refMap) {
		String keyName = MAP_KEY_PREFIX + i;
		JsonNode propertiesNode = source.get("additionalProperties");
		if (hasId(propertiesNode)) {
			refMap.put(getId(propertiesNode), propertiesNode);
		}
		if (isArray(propertiesNode)) {
			ArrayNode arrayNode = mapper.createArrayNode();
			((ObjectNode) target).set(keyName, arrayNode);
			fillJsonNode(mapper, sourceRoot, propertiesNode, arrayNode, refMap);
		} else if (isMap(propertiesNode)) {
			ObjectNode objectNode = mapper.createObjectNode();
			((ObjectNode) target).set(keyName, objectNode);
			fillJsonNode(mapper, sourceRoot, propertiesNode, objectNode, refMap);
		} else if (isPojoPlain(propertiesNode)) {
			JsonNode jsonNode;
			if (hasProperties(propertiesNode)) {
				jsonNode = propertiesNode;
			} else {
				jsonNode = refMap.get(getRef(propertiesNode));
			}
			ObjectNode objectNode = mapper.createObjectNode();
			((ObjectNode) target).set(keyName, objectNode);
			fillJsonNode(mapper, sourceRoot, jsonNode, objectNode, refMap);
		} else {
			((ObjectNode) target).set(keyName, NullNode.getInstance());
		}
	}
	
	private static boolean isPojoPlain(JsonNode jsonNode) {
		return jsonNode.has("type") && "object".equals(jsonNode.get("type").asText()) && (jsonNode.has("properties") || jsonNode.has("$ref"));
	}

	private static boolean isArray(JsonNode jsonNode) {
		return jsonNode.has("type") && "array".equals(jsonNode.get("type").asText());
	}
	
	private static boolean isMap(JsonNode jsonNode) {
		return jsonNode.has("type") && "object".equals(jsonNode.get("type").asText()) && jsonNode.has("additionalProperties");
	}
	
	private static boolean shouldArray(JsonNode jsonNode) {
		return isArray(jsonNode);
	}
	
	private static boolean shouldObject(JsonNode jsonNode) {
		return jsonNode.has("type") && "object".equals(jsonNode.get("type").asText());
	}
	
	private static JsonNode getArrayItems(JsonNode jsonNode) {
		return jsonNode.get("items");
	}
	
	private static boolean hasId(JsonNode jsonNode) {
		return jsonNode.has("id");
	}
	
	private static String getId(JsonNode jsonNode) {
		return jsonNode.get("id").asText();
	}
	
	private static String getRef(JsonNode jsonNode) {
		return jsonNode.get("$ref").asText();
	}
	
	private static boolean hasProperties(JsonNode jsonNode) {
		return jsonNode.has("properties");
	}
	
	private static JsonNode getProperties(JsonNode jsonNode) {
		return jsonNode.get("properties");
	}
}

怎么使用

测试用的实体类

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>
 类似资料: