2019-11-12 14:58:17 +00:00
|
|
|
package annotation
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
luReflect "git.loafle.net/loafer/util-go/reflect"
|
|
|
|
)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
registry = newRegistry()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Definition is struct
|
|
|
|
type Definition struct {
|
|
|
|
t reflect.Type
|
|
|
|
rt reflect.Type
|
|
|
|
}
|
|
|
|
|
|
|
|
// Regist is interface
|
|
|
|
type Regist interface {
|
|
|
|
// Register is method
|
2019-11-13 13:39:48 +00:00
|
|
|
Register(t reflect.Type) error
|
2019-11-12 14:58:17 +00:00
|
|
|
// Parse is method
|
|
|
|
Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Registry is struct
|
|
|
|
type Registry struct {
|
|
|
|
definitions map[string]*Definition
|
|
|
|
}
|
|
|
|
|
|
|
|
var registry Regist
|
|
|
|
|
|
|
|
func newRegistry() Regist {
|
|
|
|
r := &Registry{}
|
|
|
|
r.definitions = make(map[string]*Definition, 0)
|
|
|
|
|
|
|
|
return r
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register is method
|
2019-11-13 13:39:48 +00:00
|
|
|
func Register(t reflect.Type) error {
|
|
|
|
return registry.Register(t)
|
2019-11-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Register is method
|
2019-11-13 13:39:48 +00:00
|
|
|
func (r *Registry) Register(t reflect.Type) error {
|
2019-11-12 14:58:17 +00:00
|
|
|
rt, _, _ := luReflect.GetTypeInfo(t)
|
|
|
|
f := r.getTypeAnnotationField(t)
|
|
|
|
if nil == f {
|
2019-11-13 13:39:48 +00:00
|
|
|
return fmt.Errorf("Annotation: This type[%s] is not Annotation. use TypeAnnotation", rt.Name())
|
2019-11-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
name := r.parseAnnotationMeta(f.Tag)
|
|
|
|
|
|
|
|
if _, ok := r.definitions[name]; ok {
|
2019-11-13 13:39:48 +00:00
|
|
|
return fmt.Errorf("Annotation: name[%s] of annotation exist already", name)
|
2019-11-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
def := &Definition{
|
|
|
|
t: t,
|
|
|
|
rt: rt,
|
|
|
|
}
|
|
|
|
|
|
|
|
r.definitions[name] = def
|
2019-11-13 13:39:48 +00:00
|
|
|
return nil
|
2019-11-12 14:58:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Parse is method
|
|
|
|
func Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
|
|
|
|
return registry.Parse(tag)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse is method
|
|
|
|
func (r *Registry) Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
|
|
|
|
s := strings.Trim(tag.Get(AnnotationTag), " ")
|
|
|
|
if "" == s {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
annotations, err := r.splitAnnotation(s)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if nil == annotations || 0 == len(annotations) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
rKVs := make(map[reflect.Type]Annotation, 0)
|
|
|
|
for name, attributes := range annotations {
|
|
|
|
t, annotation, err := r.buildAnnotation(name, attributes)
|
|
|
|
if nil != err {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
rKVs[t] = annotation
|
|
|
|
}
|
|
|
|
|
|
|
|
return rKVs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Registry) getTypeAnnotationField(t reflect.Type) *reflect.StructField {
|
|
|
|
rt, _, _ := luReflect.GetTypeInfo(t)
|
|
|
|
if reflect.Struct != rt.Kind() {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < rt.NumField(); i++ {
|
|
|
|
f := rt.Field(i)
|
|
|
|
|
|
|
|
if f.Anonymous {
|
|
|
|
if f.Type == TypeAnnotationType {
|
|
|
|
return &f
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Registry) parseAnnotationMeta(tag reflect.StructTag) string {
|
|
|
|
return strings.Trim(tag.Get(AnnotationMetaTag), " ")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Registry) splitAnnotation(s string) (map[string]string, error) {
|
|
|
|
ss := make(map[string]string, 0)
|
|
|
|
ts := s
|
|
|
|
for {
|
|
|
|
as := strings.Index(ts, AnnotationChar)
|
|
|
|
if -1 == as {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
aas := strings.Index(ts, AnnotationStartChar)
|
|
|
|
aae := strings.Index(ts, AnnotationEndChar)
|
|
|
|
|
|
|
|
aName := ts[as:aas]
|
|
|
|
aAttributes := ts[aas+1 : aae]
|
|
|
|
|
|
|
|
if 0 < len(aAttributes) {
|
|
|
|
ss[aName] = aAttributes
|
|
|
|
} else {
|
|
|
|
ss[aName] = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(ts) <= (aae + 1) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
ts = ts[aae+1:]
|
|
|
|
}
|
|
|
|
|
|
|
|
return ss, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Registry) buildAnnotation(name string, attributes string) (reflect.Type, Annotation, error) {
|
|
|
|
def, ok := r.definitions[name]
|
|
|
|
if !ok {
|
|
|
|
return nil, nil, fmt.Errorf("There is no annotation[%s]", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
v := reflect.New(def.rt)
|
|
|
|
i := v.Interface().(Annotation)
|
|
|
|
|
|
|
|
if "" != attributes {
|
|
|
|
_json := fmt.Sprintf("{%s}", attributes)
|
|
|
|
if err := json.Unmarshal([]byte(_json), i); nil != err {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return def.t, i, nil
|
|
|
|
}
|