diff --git a/annotation/annotation.go b/annotation/annotation.go index b8af711..ddae130 100644 --- a/annotation/annotation.go +++ b/annotation/annotation.go @@ -4,11 +4,10 @@ import ( "fmt" "reflect" "strings" - - "git.loafle.net/commons_go/di" ) const ( + AnnotationTag = "annotation" AnnotationChar = "@" AnnotationStartChar = "(" AnnotationEndChar = ")" @@ -33,8 +32,8 @@ type Annotation interface { // @Inject(name? string) // @Resource(name? string) -func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) { - s := strings.Trim(tag.Get(di.AnnotationTag), " ") +func ParseAnnotation(tag reflect.StructTag) (map[string]Annotation, error) { + s := strings.Trim(tag.Get(AnnotationTag), " ") if "" == s { return nil, nil } @@ -44,7 +43,7 @@ func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) { return nil, nil } - rKVs := make([]Annotation, 0) + rKVs := make(map[string]Annotation, 0) for _, a := range annotations { a = strings.Trim(a, " ") if "" == a { @@ -61,7 +60,7 @@ func ParseAnnotation(tag reflect.StructTag) ([]Annotation, error) { if nil != err { return nil, err } - rKVs = append(rKVs, annotation) + rKVs[aName] = annotation } return rKVs, nil diff --git a/constants.go b/constants.go index bfe979d..dec394a 100644 --- a/constants.go +++ b/constants.go @@ -23,7 +23,3 @@ const ( ScopeTypeSingleton ScopeTypeTransiant ) - -const ( - AnnotationTag = "annotation" -) diff --git a/registry/definition.go b/registry/definition.go index 08fd76c..88db906 100644 --- a/registry/definition.go +++ b/registry/definition.go @@ -14,16 +14,24 @@ type TypeDefinition struct { Type reflect.Type RealType reflect.Type - Fields map[string]*FieldDefinition + Fields []*FieldDefinition } type FieldDefinition struct { - PkgName string - TypeName string - Type reflect.Type - RealType reflect.Type + FieldName string + PkgName string + TypeName string + Type reflect.Type + RealType reflect.Type - Annotations []cda.Annotation + Annotations map[string]cda.Annotation +} + +func (fd *FieldDefinition) GetAnnotation(name string) cda.Annotation { + if nil == fd.Annotations { + return nil + } + return fd.Annotations[name] } func FullName(pkgName, typeName string) string { diff --git a/registry/registry.go b/registry/registry.go index 8a82b66..2c053c5 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -30,6 +30,7 @@ func newRegistry() ComponentRegistry { r := &defaultComponentRegistry{} r.definitionByType = make(map[reflect.Type]*TypeDefinition, 0) r.definitionByName = make(map[string]*TypeDefinition, 0) + r.instanceByType = make(map[reflect.Type]interface{}, 0) r.resourceByName = make(map[string]interface{}, 0) return r @@ -38,6 +39,7 @@ func newRegistry() ComponentRegistry { type defaultComponentRegistry struct { definitionByType map[reflect.Type]*TypeDefinition definitionByName map[string]*TypeDefinition + instanceByType map[reflect.Type]interface{} resourceByName map[string]interface{} } @@ -93,6 +95,8 @@ func (cr *defaultComponentRegistry) RegisterResource(name string, resource inter return nil } +// GetInstance returns instance of type +// t must be pointer of struct func GetInstance(t reflect.Type) (interface{}, error) { return registry.GetInstance(t) } @@ -101,6 +105,14 @@ func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, er return nil, fmt.Errorf("DI: t[reflect.Type] is nil") } + if reflect.Ptr != t.Kind() { + return nil, fmt.Errorf("DI: t[reflect.Type] must be pointer of struct") + } + + if reflect.Struct != t.Elem().Kind() { + return nil, fmt.Errorf("DI: t[reflect.Type] must be pointer of struct") + } + var err error rt, _, _ := cdur.GetTypeInfo(t) @@ -112,22 +124,60 @@ func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, er } } - v := reflect.New(rt) - i := v.Interface() - - for f, fd := range td.Fields { - + comV, ok := cr.instanceByType[td.RealType] + if ok { + return comV, nil } - return nil, nil + v := reflect.New(rt) + rv := v.Elem() + + var annotation cda.Annotation + var fV interface{} + + for _, fd := range td.Fields { + f := rv.FieldByName(fd.FieldName) + + if !f.IsValid() { + return nil, fmt.Errorf("DI: Field[%s] is not valid", fd.FieldName) + } + if !f.CanSet() { + return nil, fmt.Errorf("DI: Field[%s] can not set", fd.FieldName) + } + + annotation = fd.GetAnnotation(cda.InjectTag) + if nil != annotation { + fV, err = cr.GetInstance(fd.Type) + } + annotation = fd.GetAnnotation(cda.ResourceTag) + if nil != annotation { + n := annotation.(*cda.Resource).Name + if "" == n { + n = fd.FieldName + } + fV, err = cr.GetInstanceByName(n) + } + + if nil != err { + return nil, err + } + f.Set(reflect.ValueOf(fV)) + } + + cr.instanceByType[td.RealType] = v.Interface() + + return v.Interface(), nil } func GetInstanceByName(name string) (interface{}, error) { return registry.GetInstanceByName(name) } func (cr *defaultComponentRegistry) GetInstanceByName(name string) (interface{}, error) { - - return nil, nil + v, ok := cr.resourceByName[name] + if ok { + return v, nil + } + return nil, fmt.Errorf("DI: Resource[%s] is not exist", name) } func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefinition, error) { @@ -143,33 +193,47 @@ func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefini td.Type = t td.RealType = rt - nf := rt.NumField() - if 0 < nf { - fields := make(map[string]*FieldDefinition) - for i := 0; i < nf; i++ { - f := rt.Field(i) + fields := getFields(rt) + + if 0 < len(fields) { + td.Fields = fields + } + + return td, nil +} + +func getFields(t reflect.Type) []*FieldDefinition { + fields := make([]*FieldDefinition, 0) + rt, _, _ := cdur.GetTypeInfo(t) + if reflect.Struct != rt.Kind() { + return fields + } + + for i := 0; i < rt.NumField(); i++ { + f := rt.Field(i) + + if f.Anonymous { + fields = append(fields, getFields(f.Type)...) + } else { as, err := cda.ParseAnnotation(f.Tag) if nil != err { - return nil, err + return fields } if nil != as && 0 < len(as) { fRT, fPkgName, fTName := cdur.GetTypeInfo(f.Type) fd := &FieldDefinition{ + FieldName: f.Name, PkgName: fPkgName, TypeName: fTName, Type: f.Type, RealType: fRT, Annotations: as, } - fields[f.Name] = fd + fields = append(fields, fd) } } - - if 0 < len(fields) { - td.Fields = fields - } } - return td, nil + return fields } diff --git a/registry/registry_test.go b/registry/registry_test.go index 4b2f7dc..7206950 100644 --- a/registry/registry_test.go +++ b/registry/registry_test.go @@ -1,34 +1,45 @@ package registry import ( + "log" "reflect" "testing" - - cda "git.loafle.net/commons_go/di/annotation" ) func TestRegisterType(t *testing.T) { - RegisterType(reflect.TypeOf((*TestStruct1)(nil)), &cda.ComponentAnnotation{}) - RegisterType(reflect.TypeOf((*TestStruct2)(nil)), &cda.ComponentAnnotation{ - Name: "test1", - }) - RegisterType(reflect.TypeOf((*TestStruct3)(nil)), &cda.ComponentAnnotation{ - Name: "test2", - }) + // RegisterType(reflect.TypeOf((*TestStruct1)(nil)), &cda.ComponentAnnotation{}) + // RegisterType(reflect.TypeOf((*TestStruct2)(nil)), &cda.ComponentAnnotation{ + // Name: "test1", + // }) + // RegisterType(reflect.TypeOf((*TestStruct3)(nil)), &cda.ComponentAnnotation{ + // Name: "test2", + // }) + + // fs := getFields(reflect.TypeOf((*TestStruct3)(nil))) + // log.Printf("%v", fs) + + RegisterResource("List", []string{"dfdkf", "skgkfg"}) + + i, err := GetInstance(reflect.TypeOf((*CService)(nil))) + if nil != err { + log.Printf("%v", err) + } else { + cs := i.(*CService) + log.Printf("%v", cs) + } + } -type TestStruct1 struct { - Name1 string `annotation:"@Inject"` - Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test1)"` +type AService struct { + NameA string } -type TestStruct2 struct { - Name1 string `annotation:"@Inject"` - Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test2)"` + +type BService struct { + NameB string } -type TestStruct3 struct { - Name1 string `annotation:"@Inject"` - Name2 string `annotation:"@Inject()"` - Name3 string `annotation:"@Inject(name=test3)"` + +type CService struct { + AService *AService `annotation:"@Inject()"` + BService *BService `annotation:"@Inject()"` + List []string `annotation:"@Resource()"` }