diff --git a/annotation/annotation.go b/annotation/annotation.go index 3b3a864..b8af711 100644 --- a/annotation/annotation.go +++ b/annotation/annotation.go @@ -9,58 +9,137 @@ import ( ) 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) (map[string]Annotation, error) { - a := strings.Trim(tag.Get(di.AnnotationTag), " ") - if "" == a { +func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) { + s := strings.Trim(tag.Get(di.AnnotationTag), " ") + if "" == s { return nil, nil } - rKVs := make(map[string]Annotation) - - inject, err := ParseInject(a) - if nil != err { - return nil, err + annotations := strings.Split(s, AnnotationSpliter) + if nil == annotations || 0 == len(annotations) { + return nil, nil } - rKVs[InjectTag] = inject - resource, err := ParseResource(a) - if nil != err { - return nil, err + 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) } - rKVs[ResourceTag] = resource return rKVs, nil } -func ParseAttribute(a string, startIndex int) (map[string]string, error) { - if startIndex >= len(a) { +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 } - if AnnotationStartChar != string([]rune(a)[startIndex]) { - return nil, nil - } - - endIndex := strings.Index(a[startIndex+1:], AnnotationEndChar) - if -1 == endIndex { - return nil, fmt.Errorf("DI: Syntax error - annotation(%s) has '%s', but '%s' is not exist", a, AnnotationStartChar, AnnotationEndChar) - } - endIndex = endIndex + startIndex + 1 - - body := a[startIndex+1 : endIndex] - kvs := strings.Split(body, AnnotationAttributeSpliter) - if 0 == len(kvs) { + kvs := strings.Split(attr, AnnotationAttributeSpliter) + if nil == kvs || 0 == len(kvs) { return nil, nil } diff --git a/annotation/component.go b/annotation/component.go index d0bb5f8..26f95a9 100644 --- a/annotation/component.go +++ b/annotation/component.go @@ -5,7 +5,8 @@ import ( ) type ComponentAnnotation struct { - Names []string + Annotation + Name string InitMethod string // func (receiver interface{}, cr ComponentRegistry) error DestroyMethod string // func (receiver interface{}, cr ComponentRegistry) error Scope di.ScopeType diff --git a/annotation/inject.go b/annotation/inject.go index fcbdc09..87973a6 100644 --- a/annotation/inject.go +++ b/annotation/inject.go @@ -3,37 +3,31 @@ package annotation // @Inject(name? string) import ( - "strings" + "fmt" + "reflect" ) const ( InjectTag = "@Inject" ) +func init() { + registerAnnotation(InjectTag, reflect.TypeOf((*Inject)(nil))) +} + type Inject struct { Annotation Name string } -func ParseInject(a string) (*Inject, error) { - i := strings.Index(a, InjectTag) - if -1 == i { - return nil, nil - } - - inject := &Inject{} - - atts, err := ParseAttribute(a, i+len(InjectTag)) - if nil != err { - return nil, err - } - - for k, v := range atts { +func (a *Inject) parseAttribute(attributes map[string]string) error { + for k, v := range attributes { switch k { case "name": - inject.Name = v + a.Name = v + default: + return fmt.Errorf("Syntax error: not supported attribute[%s]", k) } } - - return inject, nil + return nil } diff --git a/annotation/resource.go b/annotation/resource.go index 6c5b12a..9d560fd 100644 --- a/annotation/resource.go +++ b/annotation/resource.go @@ -1,35 +1,31 @@ package annotation -import "strings" +import ( + "fmt" + "reflect" +) const ( ResourceTag = "@Resource" ) +func init() { + registerAnnotation(ResourceTag, reflect.TypeOf((*Resource)(nil))) +} + type Resource struct { Annotation Name string } -func ParseResource(a string) (*Resource, error) { - i := strings.Index(a, ResourceTag) - if -1 == i { - return nil, nil - } - - inject := &Resource{} - - atts, err := ParseAttribute(a, i+len(ResourceTag)) - if nil != err { - return nil, err - } - - for k, v := range atts { +func (a *Resource) parseAttribute(attributes map[string]string) error { + for k, v := range attributes { switch k { case "name": - inject.Name = v + a.Name = v + default: + return fmt.Errorf("Syntax error: not supported attribute[%s]", k) } } - - return inject, nil + return nil } diff --git a/registry/definition.go b/registry/definition.go index 61dc103..08fd76c 100644 --- a/registry/definition.go +++ b/registry/definition.go @@ -23,7 +23,7 @@ type FieldDefinition struct { Type reflect.Type RealType reflect.Type - Annotations map[string]cda.Annotation + Annotations []cda.Annotation } func FullName(pkgName, typeName string) string { diff --git a/registry/registry.go b/registry/registry.go index bec07b8..676adff 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -4,6 +4,8 @@ import ( "fmt" "log" "reflect" + "runtime" + "strings" cda "git.loafle.net/commons_go/di/annotation" cdur "git.loafle.net/commons_go/di/util/reflect" @@ -37,6 +39,12 @@ type defaultComponentRegistry struct { } func RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) { + pc, _, _, ok := runtime.Caller(1) + details := runtime.FuncForPC(pc) + if ok && details != nil { + log.Printf("called from %s\n", details.Name()) + } + registry.RegisterType(t, ca) } func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) { @@ -57,24 +65,17 @@ func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.Compone } cr.definitionByType[td.RealType] = td - names := make([]string, 0) - if nil != ca { - if nil != ca.Names && 0 < len(ca.Names) { - for _, n := range ca.Names { - names = append(names, n) - } - } - } - if 0 == len(names) { - names = append(names, td.FullName) + name := "" + if nil != ca && "" != strings.Trim(ca.Name, " ") { + name = ca.Name + } else { + name = td.TypeName } - for _, n := range names { - if eTD, ok := cr.definitionByName[n]; ok { - logging.Logger().Panic(fmt.Sprintf("DI: The name[%s] of Component is exist already type[%s]", n, eTD.FullName)) - } - cr.definitionByName[n] = td + if eTD, ok := cr.definitionByName[name]; ok { + logging.Logger().Panic(fmt.Sprintf("DI: The name[%s] of Component is exist already type[%s]", name, eTD.FullName)) } + cr.definitionByName[name] = td } func GetInstance(t reflect.Type) (interface{}, error) { @@ -115,12 +116,12 @@ func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefini } rt, pkgName, tName := cdur.GetTypeInfo(t) - cd := &TypeDefinition{} - cd.FullName = FullName(pkgName, tName) - cd.PkgName = pkgName - cd.TypeName = tName - cd.Type = t - cd.RealType = rt + td := &TypeDefinition{} + td.FullName = FullName(pkgName, tName) + td.PkgName = pkgName + td.TypeName = tName + td.Type = t + td.RealType = rt nf := rt.NumField() if 0 < nf { @@ -146,9 +147,9 @@ func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefini } if 0 < len(fields) { - cd.Fields = fields + td.Fields = fields } } - return cd, nil + return td, nil } diff --git a/registry/registry_test.go b/registry/registry_test.go index 7601aee..4b2f7dc 100644 --- a/registry/registry_test.go +++ b/registry/registry_test.go @@ -10,25 +10,25 @@ import ( func TestRegisterType(t *testing.T) { RegisterType(reflect.TypeOf((*TestStruct1)(nil)), &cda.ComponentAnnotation{}) RegisterType(reflect.TypeOf((*TestStruct2)(nil)), &cda.ComponentAnnotation{ - Names: []string{"test1", "test2"}, + Name: "test1", }) RegisterType(reflect.TypeOf((*TestStruct3)(nil)), &cda.ComponentAnnotation{ - Names: []string{"test1", "test2"}, + Name: "test2", }) } type TestStruct1 struct { Name1 string `annotation:"@Inject"` Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test)"` + Name3 string `annotation:"@Inject(name=test1)"` } type TestStruct2 struct { Name1 string `annotation:"@Inject"` Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test)"` + Name3 string `annotation:"@Inject(name=test2)"` } type TestStruct3 struct { Name1 string `annotation:"@Inject"` Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test)"` + Name3 string `annotation:"@Inject(name=test3)"` }