package annotation import ( "encoding/json" "fmt" "reflect" "strings" our "git.loafle.net/overflow/util-go/reflect" ) type Registry interface { Register(t reflect.Type) error GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error) GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error) GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) } func New(parent Registry) Registry { r := &AnnotationRegistry{ parent: parent, definitions: make(map[string]*Definition, 0), typeDefinitions: make(map[reflect.Type]*TypeDefinition, 0), } if nil == r.parent { r.parent = SystemRegistry } return r } var SystemRegistry = &AnnotationRegistry{ parent: nil, definitions: make(map[string]*Definition, 0), typeDefinitions: make(map[reflect.Type]*TypeDefinition, 0), } type AnnotationRegistry struct { parent Registry definitions map[string]*Definition typeDefinitions map[reflect.Type]*TypeDefinition } func Register(t reflect.Type) error { return SystemRegistry.Register(t) } func (r *AnnotationRegistry) Register(t reflect.Type) error { rt, _, _ := our.GetTypeInfo(t) fields := findAnnotatedFields(t, AnnotationType, false) switch len(fields) { case 0: return fmt.Errorf("type[%s] is not Annotation", rt.Name()) case 1: default: return fmt.Errorf("type[%s] have only one Annotation", rt.Name()) } f := fields[AnnotationName] name := strings.TrimSpace(f.Tag.Get(NameTag)) if "" == name { return fmt.Errorf("annotation name of type[%s] is not valid", rt.Name()) } if _, ok := r.definitions[name]; ok { return fmt.Errorf("name[%s] of annotation exist already", name) } r.definitions[name] = &Definition{ t: t, rt: rt, } return nil } func findAnnotatedFields(t reflect.Type, ft reflect.Type, deep bool) map[string]*reflect.StructField { fields := make(map[string]*reflect.StructField, 0) rt, _, _ := our.GetTypeInfo(t) if reflect.Struct != rt.Kind() { return fields } LOOP: for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) if f.Anonymous { if f.Type == ft { fields[f.Name] = &f continue LOOP } if deep { _fields := findAnnotatedFields(f.Type, ft, deep) for _n, _f := range _fields { fields[_n] = _f } } } } return fields } func (r *AnnotationRegistry) getAnnotation(f *reflect.StructField) (map[reflect.Type]Annotation, error) { annotations := make(map[reflect.Type]Annotation, 0) tag := strings.TrimSpace(f.Tag.Get(AnnotationTag)) if "" == tag { return annotations, nil } if !AnnotationRGX.MatchString(tag) { return nil, fmt.Errorf("Tag of annotation[%s] is not match", tag) } rss := AnnotationRGX.FindAllStringSubmatch(tag, -1) if nil == rss || 0 == len(rss) { return annotations, nil } for _, rs := range rss { if 3 != len(rs) { return nil, fmt.Errorf("Tag of annotation[%s] is not valid", rs[0]) } name := fmt.Sprintf("@%s", strings.TrimSpace(rs[1])) body := rs[2] if !AnnotationBodyRGX.MatchString(body) { return nil, fmt.Errorf("Body[%s] of annotation[%s] is not valid", body, name) } body = AnnotationBodyRGX.ReplaceAllStringFunc(body, func(token string) string { switch len(token) { case 0, 1, 2: return "\"\"" default: return strings.Replace(fmt.Sprintf("\"%s\"", token[1:len(token)-1]), "\\'", "'", -1) } }) body = fmt.Sprintf("{%s}", strings.TrimSpace(body)) def, ok := r.definitions[name] if !ok { return nil, fmt.Errorf("annotation[%s] is not exist", name) } v := reflect.New(def.rt) i := v.Interface() err := json.Unmarshal([]byte(body), i) if nil != err { return nil, fmt.Errorf("Unmarshal failed %v", err) } annotations[def.t] = i } return annotations, nil } func (r *AnnotationRegistry) getTypeDefinition(t reflect.Type) (*TypeDefinition, error) { rt, _, _ := our.GetTypeInfo(t) if reflect.Struct != rt.Kind() { return nil, fmt.Errorf("type[%s] is not struct", rt.Name()) } td, ok := r.typeDefinitions[t] if ok { return td, nil } td = &TypeDefinition{ t: t, rt: rt, } LOOP: for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) if f.Anonymous { if f.Type == TypeAnnotationType { if 0 < len(td.typeAnnotation) { return nil, fmt.Errorf("TypeAnnotation of type[%s] be defined one more time", rt.Name()) } as, err := r.getAnnotation(&f) if nil != err { return nil, err } if 0 == len(as) { continue LOOP } td.typeAnnotation = as } } else { if f.Type == MethodAnnotationType { as, err := r.getAnnotation(&f) if nil != err { return nil, err } if 0 == len(as) { continue LOOP } if 0 == len(td.methodAnnotation) { td.methodAnnotation = make(map[string]map[reflect.Type]Annotation, 0) } td.methodAnnotation[f.Name] = as continue LOOP } else { as, err := r.getAnnotation(&f) if nil != err { return nil, err } if 0 == len(as) { continue LOOP } if 0 == len(td.fieldAnnotation) { td.fieldAnnotation = make(map[string]map[reflect.Type]Annotation, 0) } td.fieldAnnotation[f.Name] = as continue LOOP } } } r.typeDefinitions[t] = td return td, nil } func GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error) { return SystemRegistry.GetTypeAnnotation(t, at) } func (r *AnnotationRegistry) GetTypeAnnotation(t reflect.Type, at reflect.Type) (Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.typeAnnotation) { return nil, fmt.Errorf("TypeAnnotation of type[%s] is not exist", td.rt.Name()) } a, ok := td.typeAnnotation[at] if !ok { return nil, fmt.Errorf("Annotation[%s] of type[%s] is not exist", at.Name(), td.rt.Name()) } return a, nil } func GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error) { return SystemRegistry.GetTypeAnnotations(t) } func (r *AnnotationRegistry) GetTypeAnnotations(t reflect.Type) (map[reflect.Type]Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.typeAnnotation) { return nil, fmt.Errorf("TypeAnnotation of type[%s] is not exist", td.rt.Name()) } return td.typeAnnotation, nil } func GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) { return SystemRegistry.GetFieldAnnotation(t, name, at) } func (r *AnnotationRegistry) GetFieldAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.fieldAnnotation) { return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name()) } as, ok := td.fieldAnnotation[name] if !ok || 0 == len(as) { return nil, fmt.Errorf("Field[%s] Annotation of type[%s] is not exist", name, td.rt.Name()) } a, ok := as[at] if !ok { return nil, fmt.Errorf("Annotation[%s] of field[%s] in type[%s] is not exist", at.Name(), name, td.rt.Name()) } return a, nil } func GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) { return SystemRegistry.GetFieldAnnotations(t, name) } func (r *AnnotationRegistry) GetFieldAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.fieldAnnotation) { return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name()) } as, ok := td.fieldAnnotation[name] if !ok || 0 == len(as) { return nil, fmt.Errorf("Field[%s] Annotation of type[%s] is not exist", name, td.rt.Name()) } return as, nil } func GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) { return SystemRegistry.GetAllFieldAnnotations(t) } func (r *AnnotationRegistry) GetAllFieldAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.fieldAnnotation) { return nil, fmt.Errorf("FieldAnnotation of type[%s] is not exist", td.rt.Name()) } return td.fieldAnnotation, nil } func GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) { return SystemRegistry.GetMethodAnnotation(t, name, at) } func (r *AnnotationRegistry) GetMethodAnnotation(t reflect.Type, name string, at reflect.Type) (Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.methodAnnotation) { return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name()) } as, ok := td.methodAnnotation[name] if !ok || 0 == len(as) { return nil, fmt.Errorf("Method[%s] Annotation of type[%s] is not exist", name, td.rt.Name()) } a, ok := as[at] if !ok { return nil, fmt.Errorf("Annotation[%s] of method[%s] in type[%s] is not exist", at.Name(), name, td.rt.Name()) } return a, nil } func GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) { return SystemRegistry.GetMethodAnnotations(t, name) } func (r *AnnotationRegistry) GetMethodAnnotations(t reflect.Type, name string) (map[reflect.Type]Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.methodAnnotation) { return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name()) } as, ok := td.methodAnnotation[name] if !ok || 0 == len(as) { return nil, fmt.Errorf("Method[%s] Annotation of type[%s] is not exist", name, td.rt.Name()) } return as, nil } func GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) { return SystemRegistry.GetAllMethodAnnotations(t) } func (r *AnnotationRegistry) GetAllMethodAnnotations(t reflect.Type) (map[string]map[reflect.Type]Annotation, error) { td, err := r.getTypeDefinition(t) if nil != err { return nil, err } if 0 == len(td.methodAnnotation) { return nil, fmt.Errorf("MethodAnnotation of type[%s] is not exist", td.rt.Name()) } return td.methodAnnotation, nil }