jsonschema2pojo - 二次封装(基于json内容生成JavaBean代码)-openMetaData
概述
依赖: https://mvnrepository.com/artifact/org.jsonschema2pojo/jsonschema2pojo-core
文档: https://github.com/joelittlejohn/jsonschema2pojo/wiki/Getting-Started
仓库地址: https://github.com/joelittlejohn/jsonschema2pojo
代码
核心代码
pom.xml
<!-- https://mvnrepository.com/artifact/org.jsonschema2pojo/jsonschema2pojo-core -->
<dependency>
<groupId>org.jsonschema2pojo</groupId>
<artifactId>jsonschema2pojo-core</artifactId>
<version>1.1.2</version>
</dependency>
Json2PojoCodeGeneratorConfig.java == 配置类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Json2PojoCodeGeneratorConfig implements CodeGeneratorConfig {
/**
* 用于解析成Bean的json内容
*/
@ApiModelProperty(value = "待解析的json内容(jsonContent)", required = true)
String jsonContent;
/**
* 结果Bean的类名
* 不设置则为【TestBean】
*/
@ApiModelProperty(value = "生成的Bean的类名(pojoClassName)")
String pojoClassName;
/**
* 结果Bean的包名
* 不设置则使用工具类默认包名
*/
@ApiModelProperty(value = "生成的Bean的报名(pojoPackageName)")
String pojoPackageName;
/**
* 解码
* @param jsonContent
*/
public void setJsonContent(String jsonContent) {
this.jsonContent = URLUtil.decode(jsonContent);
}
@Override
public GenerateCodeTypeEnum generateCodeTypeEnum() {
return GenerateCodeTypeEnum.JSON2POJO;
}
}
MyAbstractTypeInfoAwareAnnotator.java == 注解控制配置类
@Setter
@Getter
public class MyAbstractTypeInfoAwareAnnotator extends AbstractTypeInfoAwareAnnotator {
/**
* 是否开启使用lombok注解
*/
boolean lombokAnnotFlag = true;
/**
* 是否开启使用swagger注解
*/
boolean swaggerAnnotFlag = true;
/**
* 是否开启使用mybatisplus注解
*/
boolean mybatisPlusAnnotFlag = true;
/**
* 是否开启使用jackson注解
*/
boolean jacksonAnnotFlag = false;
public MyAbstractTypeInfoAwareAnnotator(GenerationConfig generationConfig) {
super(generationConfig);
}
@Override
protected void addJsonTypeInfoAnnotation(JDefinedClass clazz, String propertyName) {
}
/**
* 类上的注解
*/
@Override
public void propertyInclusion(JDefinedClass clazz, JsonNode schema) {
if (lombokAnnotFlag) {
clazz.annotate(Data.class);
clazz.annotate(ToString.class).param(LambdaUtil.getMethodName(ToString::callSuper), true);
clazz.annotate(Builder.class);
clazz.annotate(NoArgsConstructor.class);
clazz.annotate(AllArgsConstructor.class);
clazz.annotate(Accessors.class).param(LambdaUtil.getMethodName(Accessors::chain), true);
}
if (mybatisPlusAnnotFlag) {
clazz.annotate(TableName.class).param(LambdaUtil.getMethodName(TableName::value), StrUtil.toUnderlineCase(clazz.name()));
}
if (swaggerAnnotFlag) {
clazz.annotate(ApiModel.class).param(LambdaUtil.getMethodName(ApiModel::description), clazz.name());
}
}
/**
* 属性字段上的注解
*/
@Override
public void propertyField(JFieldVar field, JDefinedClass clazz, String propertyName, JsonNode propertyNode) {
if (mybatisPlusAnnotFlag) {
field.annotate(TableField.class).param("value", StrUtil.toUnderlineCase(propertyName));
}
if (swaggerAnnotFlag) {
field.annotate(ApiModelProperty.class).param("value", propertyName);
}
if (jacksonAnnotFlag) {
field.annotate(JsonProperty.class).param("value", propertyName);
}
}
}
MyJsonschema2pojoConfig.java == 注解控制配置类
public class MyJsonschema2pojoConfig {
/**
* 总体配置
* @param includeGetAndSetFlag 是否需要get\set代码
* @return
*/
public static GenerationConfig getGenerationConfig(boolean includeGetAndSetFlag) {
return new DefaultGenerationConfig() {
@Override
public boolean isIncludeAllPropertiesConstructor() {
return false;
}
/**
* 使用json内容进行构建javaBean
* @return
*/
@Override
public SourceType getSourceType() {
return SourceType.JSON;
}
@Override
public boolean isGenerateBuilders() { // set config option by overriding method
return false;
}
@Override
public AnnotationStyle getAnnotationStyle() {
return AnnotationStyle.NONE;
}
@Override
public boolean isIncludeAdditionalProperties() {
return false;
}
@Override
public boolean isIncludeGetters() {
return includeGetAndSetFlag;
}
@Override
public boolean isIncludeSetters() {
return includeGetAndSetFlag;
}
@Override
public boolean isIncludeToString() {
return false;
}
@Override
public boolean isSerializable() {
return true;
}
@Override
public boolean isIncludeGeneratedAnnotation() {
return false;
}
@Override
public boolean isIncludeHashcodeAndEquals() {
return false;
}
@Override
public String getTargetVersion() {
return "1.8";
}
@Override
public InclusionLevel getInclusionLevel() {
return InclusionLevel.ALWAYS;
}
};
}
public static GenerationConfig getGenerationConfig() {
return getGenerationConfig(false);
}
/**
* 生成的注解配置
* @param generationConfig
* @return
*/
public static MyAbstractTypeInfoAwareAnnotator getAnnotator(GenerationConfig generationConfig) {
return new MyAbstractTypeInfoAwareAnnotator(generationConfig);
}
/**
* 自定义总体配置+注解配置
* @return
*/
public static SchemaMapper getSchemaMapper(GenerationConfig config, MyAbstractTypeInfoAwareAnnotator myAbstractTypeInfoAwareAn) {
return new SchemaMapper(new RuleFactory(config, myAbstractTypeInfoAwareAn, new SchemaStore()), new SchemaGenerator());
}
/**
* 默认总体配置+注解配置
* @return
*/
public static SchemaMapper getDefaultSchemaMapper() {
GenerationConfig generationConfig = getGenerationConfig();
MyAbstractTypeInfoAwareAnnotator annotator = getAnnotator(generationConfig);
return getSchemaMapper(generationConfig,annotator);
}
}
MyCodeWriter.java == 用于获取代码生成结果
public class MyCodeWriter extends CodeWriter {
private final PrintStream out;
/**
* @param os
* This stream will be closed at the end of the code generation.
*/
public MyCodeWriter( OutputStream os ) {
this.out = new PrintStream(os);;
}
@Override
public OutputStream openBinary(JPackage pkg, String fileName) throws IOException {
String pkgName = pkg.name();
if(pkgName.length()!=0) pkgName += '.';
return new FilterOutputStream(out) {
public void close() {
// don't let this stream close
}
};
}
@Override
public void close() throws IOException {
out.close();
}
}
Json2PojoCodeGeneratorUtil.java == 静态封装方便使用
public class Json2PojoCodeGeneratorUtil implements CodeGenerator {
@SneakyThrows
public static String json2pojo(String jsonContent) {
return json2pojo(jsonContent, "TestBean", ClassUtil.getPackage(Json2PojoCodeGeneratorUtil.class));
}
/**
* json内容转成Bean代码
* @param jsonContent json内容
* @param pojoClassName 生成的Bean的Class名字
* @param pojoPackageName 生成的Bean的包名字
* @return
*/
@SneakyThrows
public static String json2pojo(String jsonContent, String pojoClassName, String pojoPackageName) {
return json2pojo(Json2PojoCodeGeneratorConfig.builder()
.jsonContent(jsonContent)
.pojoClassName(pojoClassName)
.pojoPackageName(pojoPackageName)
.build());
}
/**
* json内容转成Bean代码
* @param json2PojoGenerateConfig 配置信息
* @return
*/
@SneakyThrows
public static String json2pojo(Json2PojoCodeGeneratorConfig json2PojoGenerateConfig) {
String jsonContent = json2PojoGenerateConfig.getJsonContent();
Assert.isTrue(JSONUtil.isTypeJSON(jsonContent), "非JSON内容,请检查");
String pojoClassName = StrUtil.blankToDefault(json2PojoGenerateConfig.getPojoClassName(), "TestBean");
String pojoPackageName = StrUtil.blankToDefault(json2PojoGenerateConfig.getPojoPackageName(), ClassUtil.getPackage(Json2PojoCodeGeneratorUtil.class));
//1. 生成配置设置
SchemaMapper mapper = MyJsonschema2pojoConfig.getDefaultSchemaMapper();
JCodeModel codeModel = new JCodeModel();
mapper.generate(codeModel, pojoClassName, pojoPackageName, jsonContent);
//2. 开始生成代码
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
MyCodeWriter myCodeWriter = new MyCodeWriter(byteArrayOutputStream);
codeModel.build(myCodeWriter);
//3. 获取结果
String result = new String(byteArrayOutputStream.toByteArray());
return StrUtil.trim(result);
}
@Override
public GenerateCodeTypeEnum generateCodeTypeEnum() {
return GenerateCodeTypeEnum.JSON2POJO;
}
@Override
public String generate(CodeGeneratorConfig generatorConfig) {
return json2pojo((Json2PojoCodeGeneratorConfig) generatorConfig);
}
}
测试
Json2PojoCodeUtilTestGenerator.java
class Json2PojoCodeUtilTestGenerator {
public static String jsonContent = null;
@BeforeAll
static void before() {
LinkInfo linkInfo = LinkInfo.builder().shortLink("fsdfdsfdsf")
.desc("的方式范德萨范德萨")
.uuid("fdsfdsfds").build();
linkInfo.setId(432432l);
jsonContent = JSONUtil.toJsonStr(linkInfo);
Console.log(jsonContent);
}
@Test
void json2pojo() {
String pojoCode = Json2PojoCodeGeneratorUtil.json2pojo(jsonContent);
Console.log(pojoCode);
}
@Test
void testJson2pojo() {
String pojoCode = Json2PojoCodeGeneratorUtil.json2pojo(jsonContent,"Test", "work.linruchang.lrcutilsweb.consts");
Console.log(pojoCode);
}
}
Jsonschema2pojo中json schema规范写法_jsonschema2pojo.generate-CSDN博客
简介
日常开发中,json数据格式经常会被用到,其简单易懂的写法(对人与计算机皆如此)以及其轻量级特性非常适用于网络间的数据传递。json数据格式与java对象会经常进行相互转换,本文探讨的是json to java的转换。
Jsonschema2pojo即是一种json转换java的工具
主流JSON库
在解决json2java的问题时,一般使用四种主流的JSON库来进行json解析:
- JSON.simple
- GSON
- Jackson
- JSONP
Jsonschema2pojo
Jsonschema2pojo支持jackson1,jackson2,gson三种规范,基于这些规范对json数据进行解析,相应的,json数据也就需要有它本身一定的写法规范,Jsonschema2pojo定义了json schema的规范和书写方式。
Json Schema feature support
这里,我就常用的以及一些扩展的书写规范向大家一一说明,也提供了一些例子供参考。
下表为json schema书写过程中固定的一些rule,请先简单阅读:
JSON Schema rule | Supported | Since | Note |
---|---|---|---|
type (Simple) | Yes | 0.1.0 | |
type (Union) | No | ||
properties | Yes | 0.1.0 | |
patternProperties | No | ||
additionalProperties | Yes | 0.1.3 | |
items | Yes | 0.1.0 | |
additionalItems | No | ||
required | Yes | 0.1.6 | |
optional | Yes | 0.1.0 | Deprecated |
dependencies | No | ||
minimum, maximum | Yes | 0.3.2 | Via optional JSR-303 annotations |
exclusiveMinimum, exclusiveMaximum | No | ||
minItems, maxItems | Yes | 0.3.2 | Via optional JSR-303 annotations |
uniqueItems | Yes | 0.1.0 | |
pattern | Yes | 0.3.2 | Via optional JSR-303 annotations |
minLength, maxLength | Yes | 0.3.4 | Via optional JSR-303 annotations |
enum | Yes | 0.1.0 | |
default | Yes | 0.1.7 | |
title | Yes | 0.1.6 | |
description | Yes | 0.1.0 | |
format | Yes | 0.1.0 | |
divisibleBy | No | ||
disallow | No | ||
extends | Yes | 0.1.8 | |
id | No | ||
$ref | Yes | 0.1.6 | Supports absolute, relative, slash & dot delimited fragment paths, self-ref |
$schema | No |
properties
schema
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string"
}
}
}
java
public class MyObject {
private String foo;
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
}
properties用于指定schema的参数,转换为pojo后,properties中的属性foo会转换为java对象的属性foo,”type”用来指定对象或属性的类型
type
指定所定义的有类型概念的数据类型,下表为json schema中type声明类型与pojo中声明类型间的对应关系:
Schema | typeJava | type |
---|---|---|
string | java.lang.String | |
number | java.lang.Double | |
integer | java.lang.Integer | |
boolean | java.lang.Boolean | |
object | generated Java type | |
array | java.util.List | |
array (with “uniqueItems”:true) | java.util.Set | |
null | java.lang.Object | |
any | java.lang.Object |
additionalProperties
schema1
{
"type" : "object",
"additionalProperties" : {}
}
java1
public class MyObject {
private java.util.Map<String, Object> additionalProperties = new java.util.HashMap<String, Object>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
additionalProperties为true,会生成Map作为传入参数中附加参数的接受器,false则不生成,写成“{}”等同于true。 你也可以通过指定additionalProperties的数据类型来约束生成的结果。
schema2
{
"type" : "object",
"additionalProperties" : {
"type" : "number"
}
}
java2
public class MyObject {
private java.util.Map<String, Double> additionalProperties = new java.util.HashMap<String, Double>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, Double> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, Double value) {
this.additionalProperties.put(name, value);
}
}
上面将additionalProperties的类型改为Double,pojo中属性的泛型就会变为<String, Double>
如果将type指定为object(我的json文件名为source.json)
schema3
{
"type" : "object",
"additionalProperties" : {
"type" : "object"
}
}
java3
public class Source{
private java.util.Map<String, SourceProperty> additionalProperties = new java.util.HashMap<String, SourceProperty>();
@org.codehaus.jackson.annotate.JsonAnyGetter
public java.util.Map<String, SourceProperty> getAdditionalProperties() {
return this.additionalProperties;
}
@org.codehaus.jackson.annotate.JsonAnySetter
public void setAdditionalProperties(String name, SourceProperty value) {
this.additionalProperties.put(name, value);
}
}
如上,会生成一个以主文件名为前缀,Property为后缀的类(SourceProperty)作为additionalProperties的value类型,该类中则有:
java4
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
array
schema
{
"type" : "object",
"properties" : {
"myArrayProperty" : {
"type" : "array",
"items" : {
"type" : "string"
}
}
}
}
array写法如上即会生成Array<string>
类型的参数myArrayProperty,如果在myArrayProperty指定“uniqueItems”:true,生成的集合则为Set<>. 对于items,可以$ref(后面介绍)引用其他jsonschema文件,也可以直接在其下编写jsonschema,会生成一个以集合参数为名称(MyArrayProperty)的对象作为该集合的泛型
enum
schema
{
"type" : "object",
"properties" : {
"myEnum" : {
"type" : "string",
"enum" : ["one", "secondOne", "3rd one"]
}
}
}
java
@Generated("com.googlecode.jsonschema2pojo")
public static enum MyEnum {
ONE("one"),
SECOND_ONE("secondOne"),
_3_RD_ONE("3rd one");
private final String value;
private MyEnum(String value) {
this.value = value;
}
@JsonValue
@Override
public String toString() {
return this.value;
}
@JsonCreator
public static MyObject.MyEnum fromValue(String value) {
for (MyObject.MyEnum c: MyObject.MyEnum.values()) {
if (c.value.equals(value)) {
return c;
}
}
throw new IllegalArgumentException(value);
}
}
enum作为枚举写法经常被使用,比较简单,不详细介绍
format
可以给属性指定format规则,它会影响你的参数类型,和type对比,format的优先级更高,format的规则列表如下:
Format value | Java type |
---|---|
“date-time” | java.util.Date |
“date” | String |
“time” | String |
“utc-millisec” | long |
“regex” | java.util.regex.Pattern |
“color” | String |
“style” | String |
“phone” | String |
“uri” | java.net.URI |
“email” | String |
“ip-address” | String |
“ipv6” | String |
“host-name” | String |
“uuid” | java.util.UUID |
anything else (unrecognised format) | type is unchanged |
extends
extends属性声明在schema层表明继承
flower.json:
{
"type" : "object"
}
rose.json
{
"type" : "object",
"extends" : {
"$ref" : "flower.json"
}
}
Rose.java:
public class Rose extends Flower {
....
}
$ref
Supported protocols
- http://, https://
- file://
- classpath:, resource:, java: (all synonyms used to resolve schemas from the classpath)
$ref同样支持内部类型的引用
{
"type" : "object",
"properties" : {
"child1" : {
"type" : "string"
},
"child2" : {
"$ref" : "#/properties/child1"
}
}
}
上面这种child2引用了child1的属性
{
"description" : "Tree node",
"type" : "object",
"properties" : {
"children" : {
"type" : "array",
"items" : {
"$ref" : "#"
}
}
}
}
这种写法将shema类型作为集合类型泛型的引用,类似于tree结构 也可以直接定位到集合的items属性作为类型(#/properties/children/items)
javaType
```
{
"javaType" : "com.other.package.CustomTypeName",
"type" : "object"
}
```
javaType允许指定属性类型或类名称为java类(已存在或不存在的),如此生成会创建一个CustomTypeName类,并将属性类型指定为该类 如果不加”type” : “object”,则不会生成对应类,但是属性类型依然为该类名,报错而已 当然,你也可以直接指定已有的封装类
javaEnumNames
schema
{
"type" : "object",
"properties" : {
"foo" : {
"type" : "string",
"enum" : ["H","L"],
"javaEnumNames" : ["HIGH","LOW"]
}
}
}
java
public enum Foo {
HIGH("H"),
LOW("L")
...
}
javaEnumNames是对于enum的扩展,可以指定java中的enum列表具体名称
javaInterfaces
schema
{
"javaInterfaces" : ["java.io.Serializable", "Cloneable"],
"type" : "object"
}
java
public class FooBar implements Serializable, Cloneable
{
...
}
这个好理解,声明接口
javaName
该属性用于指定类或属性的生成名称
schema
{
"type": "object",
"properties": {
"a": {
"javaName": "b",
"type": "string"
}
}
}
java
public class MyClass {
@JsonProperty("a")
private String b;
@JsonProperty("a")
public String getB() {
return b;
}
@JsonProperty("a")
public void setB(String b) {
this.b = b;
}
}
如果使用在主schema级别,可以直接指定对应的类名