JSchema Specification

xkrivzooh2022年8月31日
大约 3 分钟

JSchema Specification

jSchema

jSchema is a Schema specially designed and developed for the Java ecosystem. It is described by JSON, which is convenient for developers to use in scenarios that need to define, transmit, and store data structures or function structures.

Core Futures

  • Built-in support for all basic types in the java programming language and corresponding wrapper types, such as int/Integer/long/Long/float/Float...
  • Built-in support for common collection types in the java programming language, such as Array/List/Set/Map.
  • Type descriptions that support nested combinations of collection types, such as Map<List<String>, Map<Integer, Long>>.
  • Provide TypeSchema specially used to describe basic types, collection types, user-defined class structure.
  • Provide FunctionSchema to support function structure description.
  • Type structure description, supports a variety of built-in annotations, such as @NotNull/@Default/@Alias/@Doc/@Meta/@Ignore…
  • Supports the JSR 380 (also known as Bean Validation 2.0) specification and provides an easy-to-use data validation implementation.

JSchema Specification

This document defines jSchema. It is intended to be the authoritative specification. Implementations of jSchema must adhere to this document.

Schema Declaration

A Schema is represented in JSON by one of:

  • A JSON string, naming a defined type.
  • A JSON object, of the form:
{
  "type": "typeName"
  ...attributes...
}

where typeName is either a primitive or derived type name, as defined below. Attributes not defined in this document are permitted as metadata, but must not affect the format of serialized data.

Schema Category

jSchema supports two kinds of schemas:

  • TypeSchema
  • FunctionSchema

TypeSchema

TypeSchema is mainly used to describe types in Java. Such as primitive types, arrays, collections, custom classes, etc.

Generate TypeSchema

Generating TypeSchema requires using the TypeSchema.getSchema function. The simple usage is as follows:

public class TypeSchemaTest {

    public static class User {
        String name;
        int age;
    }

    @Test
    public void test1() {
        TypeSchema schema = TypeSchema.getSchema(User.class);
        System.out.println(schema.toString(true));
    }
}

The content of the TypeSchema corresponding to the User object in the sample code is as follows:

{
  "type": "record",
  "name": "User",
  "namespace": "ren.wenchao.jschema.TypeSchemaTest",
  "types": {},
  "fields": [
    {
      "name": "age",
      "type": "int"
    },
    {
      "name": "name",
      "type": "String"
    }
  ]
}

FunctionSchema

FunctionSchema is mainly used to describe the function structure in java.

Generate FunctionSchema

If we already have an object of type java.lang.reflect.Method in the context, we will use FunctionSchema.getSchema method to generate FunctionSchema, for example:

public class FunctionSchemaTest {

    static class A {

        boolean f1() {
            return true;
        }

        String f2(int a, long c) {
            return "";
        }
    }

    @Test
    public void test1() throws NoSuchMethodException {
        Method f1 = A.class.getDeclaredMethod("f1");
        System.out.println(FunctionSchema.getSchema(f1).toString(true));
        Assert.assertEquals("{\n" +
                "  \"type\" : \"function\",\n" +
                "  \"namespace\" : \"ren.wenchao.jschema.FunctionSchemaTest\",\n" +
                "  \"name\" : \"A\",\n" +
                "  \"functionName\" : \"f1\",\n" +
                "  \"doc\" : null,\n" +
                "  \"request\" : { },\n" +
                "  \"response\" : \"boolean\"\n" +
                "}", FunctionSchema.getSchema(f1).toString(true));
    }
}

But if there is no object of type java.lang.reflect.Method in our context, we need to fully construct the FunctionSchema ourselves. For your convenience, I provide the FunctionSchemaBuilder class to simplify the operation. Here is a simple example:

public class FunctionSchemaBuilderTest {


    @Test
    public void test1() {
        Parameter parameter3 = new Parameter();
        parameter3.setName("arg2");
        parameter3.setDoc("arg2Doc");
        parameter3.addProp("arg2K1", "arg2K2");
        parameter3.setSchema(TypeSchema.getSchema(Integer.class));
        parameter3.addConstraint(new NotNull("arg2不能为空"));
        parameter3.setDefaultValue("1");


        FunctionSchemaBuilder builder = FunctionSchemaBuilder.builder()
                .namespace("ren.wenchao.jschema.FunctionSchemaTest")
                .name("A")
                .functionName("f1")
                .doc("doc")
                .requestParameter("arg0", "arg0Doc", TypeSchema.getSchema(int.class))
                .requestParameter("arg1", "arg1Doc", TypeSchema.getSchema(int.class))
                .requestParameter(parameter3)
                .response(TypeSchema.getSchema(int.class));
        FunctionSchema functionSchema = builder.build();
        System.out.println(functionSchema.toString(true));
        Assert.assertEquals("{\n" +
                "  \"type\" : \"function\",\n" +
                "  \"namespace\" : \"ren.wenchao.jschema.FunctionSchemaTest\",\n" +
                "  \"name\" : \"A\",\n" +
                "  \"functionName\" : \"f1\",\n" +
                "  \"doc\" : \"doc\",\n" +
                "  \"request\" : {\n" +
                "    \"arg0\" : {\n" +
                "      \"doc\" : \"arg0Doc\",\n" +
                "      \"props\" : { },\n" +
                "      \"constraints\" : { },\n" +
                "      \"type\" : \"int\",\n" +
                "      \"pos\" : \"0\"\n" +
                "    },\n" +
                "    \"arg1\" : {\n" +
                "      \"doc\" : \"arg1Doc\",\n" +
                "      \"props\" : { },\n" +
                "      \"constraints\" : { },\n" +
                "      \"type\" : \"int\",\n" +
                "      \"pos\" : \"1\"\n" +
                "    },\n" +
                "    \"arg2\" : {\n" +
                "      \"doc\" : \"arg2Doc\",\n" +
                "      \"props\" : {\n" +
                "        \"arg2K1\" : \"arg2K2\"\n" +
                "      },\n" +
                "      \"constraints\" : {\n" +
                "        \"NotNull\" : {\n" +
                "          \"message\" : \"arg2不能为空\"\n" +
                "        }\n" +
                "      },\n" +
                "      \"type\" : \"Integer\",\n" +
                "      \"default\" : \"1\",\n" +
                "      \"pos\" : \"2\"\n" +
                "    }\n" +
                "  },\n" +
                "  \"response\" : \"int\"\n" +
                "}", functionSchema.toString(true));

    }
}

Schema Types

Primitive Types

jSchema type string representationJava Type
bytebyte
shortshort
intint
longlong
floatfloat
doubledouble
booleanboolean
charchar
Stringjava.lang.String

Wrapper Types

jSchema type string representationSchemaTypeJava Types
ByteBYTE_WRAPPERjava.lang.Byte
ShortSHORT_WRAPPERjava.lang.Short
IntegerINT_WRAPPERjava.lang.Integer
LongLONG_WRAPPERjava.lang.Long
FloatFLOAT_WRAPPERjava.lang.Float
DoubleDOUBLE_WRAPPERjava.lang.Double
BooleanBOOLEAN_WRAPPERjava.lang.Boolean
CharacterCHAR_WRAPPERjava.lang.Character

Collection Types

jSchema type string representationJava类型
array/
Mapjava.util.Map
Listjava.util.List
Setjava.util.Set

Other Types

record

  • Records use the type name record and support the following attributes:
  • name: a JSON string providing the name of the record (required).
  • namespace, a JSON string that qualifies the name (optional);
  • doc: a JSON string providing documentation to the user of this schema (optional).
  • aliases: a JSON array of strings, providing alternate names for this record (optional).
  • fields: a JSON array, listing fields (required). Each field is a JSON object with the following attributes:
  • name: a JSON string providing the name of the field (required), and
  • doc: a JSON string describing this field for users (optional).
  • type: a schema, as defined above
  • default: A default value for this field, only used when reading instances that lack the field for schema evolution purposes.

For example, a record type schema may be defined with:

{
  "type": "record",
  "name": "User",
  "namespace": "ren.wenchao.jschema.TypeSchemaTest",
  "types": {},
  "fields": [
    {
      "name": "age",
      "type": "int"
    },
    {
      "name": "name",
      "type": "String"
    }
  ]
}

enum

enum indicates that the type is an enumeration type。

for example:

    public enum B {
        a("a");
        private final String name;

        B(String name) {
            this.name = name;
        }
    }

The corresponding schema of this enum B is expressed as follows:

{
  "type" : "enum",
  "name" : "B",
  "namespace" : "ren.wenchao.jschema.EnumSchemaTest",
  "symbols" : [ "a" ]
}

bytes

bytes indicates that this is a byte array type

null

null indicates that the type is null, which corresponds to the null keyword in java

void

void indicates that the type is void, corresponding to the void keyword in java

上次编辑于: 2022/9/13 16:52:28
Loading...