From 4a4e7cdfddd2087c557e68e3c6b7f71186c2cec7 Mon Sep 17 00:00:00 2001 From: crusader Date: Tue, 5 Dec 2017 22:28:42 +0900 Subject: [PATCH] ing --- annotation/annotation.go | 80 ++++++++++++++++++++++++++++++++ annotation/inject.go | 34 ++++++++++++++ annotation/inject_test.go | 30 ++++++++++++ annotation/resource.go | 30 ++++++++++++ annotation/resource_test.go | 30 ++++++++++++ constants.go | 4 ++ registry/definition.go | 19 +++++++- registry/registry.go | 91 ++++++++++++++++++++++++++++++++----- registry/registry_test.go | 18 ++++++++ util/reflect/type.go | 4 +- 10 files changed, 324 insertions(+), 16 deletions(-) create mode 100644 annotation/annotation.go create mode 100644 annotation/inject_test.go create mode 100644 annotation/resource_test.go create mode 100644 registry/registry_test.go diff --git a/annotation/annotation.go b/annotation/annotation.go new file mode 100644 index 0000000..3b3a864 --- /dev/null +++ b/annotation/annotation.go @@ -0,0 +1,80 @@ +package annotation + +import ( + "fmt" + "reflect" + "strings" + + "git.loafle.net/commons_go/di" +) + +const ( + AnnotationStartChar = "(" + AnnotationEndChar = ")" + AnnotationAttributeSpliter = "," + AnnotationKeyValueSpliter = "=" +) + +type Annotation interface { +} + +// @Inject(name? string) +// @Resource(name? string) +func ParseAnnotation(tag reflect.StructTag) (map[string]Annotation, error) { + a := strings.Trim(tag.Get(di.AnnotationTag), " ") + if "" == a { + return nil, nil + } + + rKVs := make(map[string]Annotation) + + inject, err := ParseInject(a) + if nil != err { + return nil, err + } + rKVs[InjectTag] = inject + + resource, err := ParseResource(a) + if nil != err { + return nil, err + } + rKVs[ResourceTag] = resource + + return rKVs, nil +} + +func ParseAttribute(a string, startIndex int) (map[string]string, error) { + if startIndex >= len(a) { + 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) { + 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 +} diff --git a/annotation/inject.go b/annotation/inject.go index 027aad8..fcbdc09 100644 --- a/annotation/inject.go +++ b/annotation/inject.go @@ -1,5 +1,39 @@ package annotation +// @Inject(name? string) + +import ( + "strings" +) + +const ( + InjectTag = "@Inject" +) + 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 { + switch k { + case "name": + inject.Name = v + } + } + + return inject, nil +} diff --git a/annotation/inject_test.go b/annotation/inject_test.go new file mode 100644 index 0000000..42362c8 --- /dev/null +++ b/annotation/inject_test.go @@ -0,0 +1,30 @@ +package annotation + +import ( + "log" + "testing" +) + +func TestParseInject(t *testing.T) { + a1 := "@Inject" + a, err := ParseInject(a1) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + + a2 := "@Inject()" + a, err = ParseInject(a2) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + + a3 := "@Inject(name=string)" + a, err = ParseInject(a3) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + +} diff --git a/annotation/resource.go b/annotation/resource.go index d78a905..6c5b12a 100644 --- a/annotation/resource.go +++ b/annotation/resource.go @@ -1,5 +1,35 @@ package annotation +import "strings" + +const ( + ResourceTag = "@Resource" +) + 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 { + switch k { + case "name": + inject.Name = v + } + } + + return inject, nil +} diff --git a/annotation/resource_test.go b/annotation/resource_test.go new file mode 100644 index 0000000..85101d9 --- /dev/null +++ b/annotation/resource_test.go @@ -0,0 +1,30 @@ +package annotation + +import ( + "log" + "testing" +) + +func TestParseResource(t *testing.T) { + a1 := "@Resource" + a, err := ParseResource(a1) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + + a2 := "@Resource( )" + a, err = ParseResource(a2) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + + a3 := "@Resource(name=string1232)" + a, err = ParseResource(a3) + if nil != err { + log.Printf("%v", err) + } + log.Printf("%v", a) + +} diff --git a/constants.go b/constants.go index dec394a..bfe979d 100644 --- a/constants.go +++ b/constants.go @@ -23,3 +23,7 @@ const ( ScopeTypeSingleton ScopeTypeTransiant ) + +const ( + AnnotationTag = "annotation" +) diff --git a/registry/definition.go b/registry/definition.go index 8df8cfb..7329985 100644 --- a/registry/definition.go +++ b/registry/definition.go @@ -1,10 +1,25 @@ package registry -import "reflect" +import ( + "reflect" -type ComponentDefinition struct { + cda "git.loafle.net/commons_go/di/annotation" +) + +type TypeDefinition struct { PkgName string TypeName string Type reflect.Type RealType reflect.Type + + Fields map[string]*FieldDefinition +} + +type FieldDefinition struct { + PkgName string + TypeName string + Type reflect.Type + RealType reflect.Type + + Annotations map[string]cda.Annotation } diff --git a/registry/registry.go b/registry/registry.go index 10df00b..c3ec83a 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -2,26 +2,43 @@ package registry import ( "fmt" + "log" "reflect" cda "git.loafle.net/commons_go/di/annotation" cdur "git.loafle.net/commons_go/di/util/reflect" ) +func init() { + registry = newRegistry() +} + +var registry ComponentRegistry + type ComponentRegistry interface { RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error - RegisterFactory(i interface{}, ca *cda.ComponentAnnotation) error GetInstance(t reflect.Type) (interface{}, error) GetInstanceByName(name string) (interface{}, error) } -type defaultComponentRegistry struct { - definitionsByType map[reflect.Type]*ComponentDefinition +func newRegistry() ComponentRegistry { + r := &defaultComponentRegistry{} + r.definitionsByType = make(map[reflect.Type]*TypeDefinition, 0) + r.definitionByName = make(map[string]*TypeDefinition, 0) - definitionByName map[string]*ComponentDefinition + return r } +type defaultComponentRegistry struct { + definitionsByType map[reflect.Type]*TypeDefinition + + definitionByName map[string]*TypeDefinition +} + +func RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error { + return registry.RegisterType(t, ca) +} func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error { if nil == t { return fmt.Errorf("DI: t[reflect.Type] is nil") @@ -30,41 +47,91 @@ func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.Compone return fmt.Errorf("DI: t[reflect.Type] must be specified but is %v", t) } - rt, pkgName, tName := cdur.GetTypeName(t) - cr.definitions[name] = rt + td, err := cr.buildDefinition(t) + if nil != err { + return err + } + + cr.definitionsByType[td.RealType] = td + + if nil != ca { + if nil != ca.Names && 0 < len(ca.Names) { + for _, n := range ca.Names { + cr.definitionByName[n] = td + } + } + } return nil } +func GetInstance(t reflect.Type) (interface{}, error) { + return registry.GetInstance(t) +} func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, error) { if nil == t { return nil, fmt.Errorf("DI: t[reflect.Type] is nil") } - + var err error cd, ok := cr.definitionsByType[t] if !ok { - cd = cr.buildDefinition(t) + cd, err = cr.buildDefinition(t) + if nil != err { + return nil, err + } } + log.Printf("%v", cd) return nil, nil } +func GetInstanceByName(name string) (interface{}, error) { + return registry.GetInstanceByName(name) +} func (cr *defaultComponentRegistry) GetInstanceByName(name string) (interface{}, error) { return nil, nil } -func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*ComponentDefinition, error) { +func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefinition, error) { if nil == t { return nil, fmt.Errorf("DI: t[reflect.Type] is nil") } - rt, pkgName, tName := cdur.GetTypeName(t) - cd := &ComponentDefinition{} + rt, pkgName, tName := cdur.GetTypeInfo(t) + cd := &TypeDefinition{} cd.PkgName = pkgName cd.TypeName = tName cd.Type = t cd.RealType = rt - return nil, nil + nf := rt.NumField() + if 0 < nf { + fields := make(map[string]*FieldDefinition) + for i := 0; i < nf; i++ { + f := rt.Field(i) + as, err := cda.ParseAnnotation(f.Tag) + if nil != err { + return nil, err + } + if nil != as && 0 < len(as) { + fRT, fPkgName, fTName := cdur.GetTypeInfo(f.Type) + + fd := &FieldDefinition{ + PkgName: fPkgName, + TypeName: fTName, + Type: f.Type, + RealType: fRT, + Annotations: as, + } + fields[f.Name] = fd + } + } + + if 0 < len(fields) { + cd.Fields = fields + } + } + + return cd, nil } diff --git a/registry/registry_test.go b/registry/registry_test.go new file mode 100644 index 0000000..0ee62f1 --- /dev/null +++ b/registry/registry_test.go @@ -0,0 +1,18 @@ +package registry + +import ( + "reflect" + "testing" + + cda "git.loafle.net/commons_go/di/annotation" +) + +func TestRegisterType(t *testing.T) { + RegisterType(reflect.TypeOf((*TestStruct)(nil)), &cda.ComponentAnnotation{}) +} + +type TestStruct struct { + Name1 string `annotation:"@Inject"` + Name2 string `annotation:"@Inject()"` + Name3 string `annotation:"@Inject(name=test)"` +} diff --git a/util/reflect/type.go b/util/reflect/type.go index c9fa3f6..f57ee99 100644 --- a/util/reflect/type.go +++ b/util/reflect/type.go @@ -14,9 +14,9 @@ func IsTypeKind(t reflect.Type, kind reflect.Kind, removePtr bool) bool { return kind == t.Kind() } -func GetTypeName(t reflect.Type) (realType reflect.Type, pkgName string, name string) { +func GetTypeInfo(t reflect.Type) (realType reflect.Type, pkgName string, name string) { if reflect.Ptr == t.Kind() { - return GetTypeName(t.Elem()) + return GetTypeInfo(t.Elem()) } return t, t.PkgPath(), t.Name()