399 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			399 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 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
 | |
| }
 |