package annotation import ( "fmt" "reflect" "strings" "git.loafle.net/commons_go/di" ) const ( AnnotationChar = "@" AnnotationStartChar = "(" AnnotationEndChar = ")" AnnotationSpliter = ";" AnnotationAttributeSpliter = "," AnnotationKeyValueSpliter = "=" ) var annotationRegistry map[string]reflect.Type func init() { annotationRegistry = make(map[string]reflect.Type, 0) } func registerAnnotation(name string, t reflect.Type) { annotationRegistry[name] = t } type Annotation interface { parseAttribute(attributes map[string]string) error } // @Inject(name? string) // @Resource(name? string) func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) { s := strings.Trim(tag.Get(di.AnnotationTag), " ") if "" == s { return nil, nil } annotations := strings.Split(s, AnnotationSpliter) if nil == annotations || 0 == len(annotations) { return nil, nil } rKVs := make([]Annotation, 0) for _, a := range annotations { a = strings.Trim(a, " ") if "" == a { continue } aName, attributes, err := ParseAnnotationItem(a) if nil != err { return nil, err } if "" == aName { continue } annotation, err := NewAnnotation(aName, attributes) if nil != err { return nil, err } rKVs = append(rKVs, annotation) } return rKVs, nil } func NewAnnotation(name string, attributes map[string]string) (Annotation, error) { t, ok := annotationRegistry[name] if !ok { return nil, fmt.Errorf("There is no annotation[%s]", name) } v := reflect.New(t.Elem()) i := v.Interface().(Annotation) if nil != attributes { i.parseAttribute(attributes) } return i, nil } func ParseAnnotationItem(a string) (name string, attributes map[string]string, err error) { s := strings.Trim(a, " ") if "" == s { return } i := strings.Index(s, AnnotationChar) if -1 == i { err = fmt.Errorf("Syntax error: annotation must be started %s", AnnotationChar) return } aStart := strings.Index(s, AnnotationStartChar) if -1 == aStart { // This is pure annotation ex)@Resource name = s return } name = s[:aStart] aEnd := strings.Index(s, AnnotationEndChar) if -1 == aEnd { // This is syntax error ex)@Resource( err = fmt.Errorf("Syntax error: annotation must be ended %s", AnnotationEndChar) return } if 1 >= aEnd-aStart { return } attr := s[aStart+1 : aEnd] attr = strings.Trim(attr, " ") if "" == attr { return } attrs, pErr := ParseAttribute(s[aStart+1 : aEnd]) if nil != pErr { err = pErr return } attributes = attrs return } func ParseAttribute(s string) (map[string]string, error) { attr := strings.Trim(s, " ") if "" == attr { return nil, nil } kvs := strings.Split(attr, AnnotationAttributeSpliter) if nil == kvs || 0 == len(kvs) { return nil, nil } rKVs := make(map[string]string) for i := 0; i < len(kvs); i++ { s := strings.Trim(kvs[i], " ") if "" == s { continue } kv := strings.Split(s, AnnotationKeyValueSpliter) k := strings.Trim(kv[0], " ") v := strings.Trim(kv[1], " ") rKVs[k] = v } return rKVs, nil }