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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZD9sglnf-1664798913277)(en-resource://database/62077:1)]

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级别,可以直接指定对应的类名

posted @ 2024-03-26 10:16  CharyGao  阅读(180)  评论(0编辑  收藏  举报