package annotation import ( "encoding/json" "fmt" "reflect" "strings" "git.loafle.net/loafer/annotation-go/annotations" 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 Register(t reflect.Type) error // Parse is method Parse(tag reflect.StructTag) (map[reflect.Type]annotations.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 func Register(t reflect.Type) error { return registry.Register(t) } // Register is method func (r *Registry) Register(t reflect.Type) error { rt, _, _ := luReflect.GetTypeInfo(t) f := r.getTypeAnnotationField(t) if nil == f { return fmt.Errorf("Annotation: This type[%s] is not Annotation. use TypeAnnotation", rt.Name()) } name := r.parseAnnotationMeta(f.Tag) if _, ok := r.definitions[name]; ok { return fmt.Errorf("Annotation: name[%s] of annotation exist already", name) } def := &Definition{ t: t, rt: rt, } r.definitions[name] = def return nil } // Parse is method func Parse(tag reflect.StructTag) (map[reflect.Type]annotations.Annotation, error) { return registry.Parse(tag) } // Parse is method func (r *Registry) Parse(tag reflect.StructTag) (map[reflect.Type]annotations.Annotation, error) { s := strings.Trim(tag.Get(AnnotationTag), " ") if "" == s { return nil, nil } am, err := r.splitAnnotation(s) if nil != err { return nil, err } if nil == am || 0 == len(am) { return nil, nil } rKVs := make(map[reflect.Type]annotations.Annotation, 0) for name, attributes := range am { 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 == annotations.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, annotations.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().(annotations.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 }