1. 背景
最近笔者在开发大数据平台XSailboat 的 数据资产目录 模块。它的其中一个功能是能定义并查看资产数据。我们支持的资产类型不仅有关系数据库表,也支持Kafka主题,hdfs上的文件等。对于Kafka主题,hdfs文件等,它们没有强模式约束和描述,但为了理解、查看和约束其中的结构化数据,我们支持在这类资产上附加上模式定义的功能。
对于模式的描述/模型,我参考了JsonSchema,OpenAPI 3.0的Schema,最终决定自己定义模式结构。这种模式结构能扩展、能转换成那些标准模式,为后续扩展和适应性调整留余地。
我期望的模式结构,举例:
{
"type":"object" ,
"fields":[{
"name" : "f0" ,
"description" : "字段0的描述信息" ,
"dataType" : "string"
} ,
{
"name" : "f1" ,
"description" : "字段1的描述信息" ,
"dataType" : {
"type" : "array" ,
"itemType" : "string"
}
} ,
....
]
}
这里我对数据类型进行了抽闲,它可以是,
基本类型:
- string
- double
- long
- int
- bool
- datetime
扩展类型
- object
- array
基本类型在我们的Java Bean定义中,它是一个类型为BaseType的JavaBean,不是字符串,所以如何序列化成JSON时,得到
{
...
"dataType" : "string" ,
...
}
的效果,而不是,文章来源:https://www.toymoban.com/news/detail-801706.html
...
"dataType" : ["BaseType" , "string"]
或者
"dataType" : {
"type" : "string"
}
...
笔者经过尝试,使用了@JsonIdentityInfo和@JsonIdentityReference解决这个问题文章来源地址https://www.toymoban.com/news/detail-801706.html
2. 代码
- com.cimstech.sailboat.common.schema.Type
package com.cimstech.sailboat.common.schema;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME, // Were binding by providing a name
include = JsonTypeInfo.As.PROPERTY, // The name is provided in a property
property = "type", // Property name is type
visible = true // Retain the value of type after deserialisation
, defaultImpl = BaseType.class // 如果不是下面指定的那两种,就缺省认定它是BaseType类型的,走它的反序列化逻辑。
)
@JsonSubTypes({//Below, we define the names and the binding classes.
@JsonSubTypes.Type(value = ArrayType.class, name = "array") ,
@JsonSubTypes.Type(value = ObjectType.class, name = "object")
})
public interface Type
{
}
- com.cimstech.sailboat.common.schema.BaseType
package com.cimstech.sailboat.common.schema;
import com.cimstech.xfront.common.reflect.XClassUtil;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.JsonIdentityReference;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import lombok.Data;
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class , property = "name"
, resolver = BaseTypeIdResolver.class , scope = BaseType.class) // 用name来做id
@JsonIdentityReference(alwaysAsId = true) // 总是使用Id来代表这个类的对象
@Data
public class BaseType implements Type
{
public static BaseType STRING = new BaseType(XClassUtil.sCSN_String) ;
public static BaseType LONG = new BaseType(XClassUtil.sCSN_Long) ;
public static BaseType DOUBLE = new BaseType(XClassUtil.sCSN_Double) ;
public static BaseType INTEGER = new BaseType(XClassUtil.sCSN_Integer) ;
public static BaseType BOOLEAN = new BaseType(XClassUtil.sCSN_Bool) ;
public static BaseType DATETIME = new BaseType(XClassUtil.sCSN_DateTime) ;
public static BaseType of(String aTypeName)
{
switch(aTypeName)
{
case XClassUtil.sCSN_String:
return STRING ;
case XClassUtil.sCSN_Long:
return LONG ;
case XClassUtil.sCSN_Double:
return DOUBLE ;
case XClassUtil.sCSN_Integer:
return INTEGER ;
case XClassUtil.sCSN_Bool:
return BOOLEAN ;
case XClassUtil.sCSN_DateTime:
return DATETIME ;
default:
throw new IllegalArgumentException("未知的基本类型:"+aTypeName) ;
}
}
final String name ;
private BaseType(String aName)
{
name = aName ;
}
@Override
public String toString()
{
return name ;
}
}
- com.cimstech.sailboat.common.schema.ArrayType
package com.cimstech.sailboat.common.schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ArrayType implements Type
{
/**
* 数组的元素类型
*/
Type itemType ;
}
- com.cimstech.sailboat.common.schema.ObjectType
package com.cimstech.sailboat.common.schema;
import java.util.List;
import lombok.Data;
@Data
public class ObjectType implements Type
{
/**
* 字段
*/
List<Field> fields ;
}
- com.cimstech.sailboat.common.schema.Field
package com.cimstech.sailboat.common.schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Field
{
String name ;
String description ;
Type dataType ;
}
- com.cimstech.sailboat.common.schema.BaseTypeIdResolver
package com.cimstech.sailboat.common.schema;
import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey;
import com.fasterxml.jackson.annotation.ObjectIdResolver;
public class BaseTypeIdResolver implements ObjectIdResolver
{
@Override
public void bindItem(IdKey aId, Object aPojo)
{
}
@Override
public Object resolveId(IdKey aId)
{
return BaseType.of(aId.key.toString()) ;
}
@Override
public ObjectIdResolver newForDeserialization(Object aContext)
{
return this ;
}
@Override
public boolean canUseFor(ObjectIdResolver aResolverType)
{
return aResolverType.getClass() == getClass() ;
}
}
到了这里,关于Jackson标签的高阶使用样例--多继承/子类、对象id、JsonIdentityInfo、JsonTypeInfo、JsonSubTypes的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!