package di import ( "fmt" "log" "reflect" "runtime" "strings" "git.loafle.net/loafer/annotation-go" luReflect "git.loafle.net/loafer/util-go/reflect" ) func init() { registry = newRegistry() } // Regist is interface type Regist interface { RegisterType(t reflect.Type) RegisterResource(name string, resource interface{}) error GetInstance(t reflect.Type) (interface{}, error) GetInstances(ts []reflect.Type) ([]interface{}, error) GetInstanceByName(name string) (interface{}, error) GetInstancesByAnnotationType(t reflect.Type) ([]interface{}, error) GetTypeAnnotation(instanceType reflect.Type, annotationType reflect.Type) annotation.Annotation GetMethodAnnotation(instanceType reflect.Type, annotationType reflect.Type, methodName string) annotation.Annotation GetMethodAnnotations(instanceType reflect.Type, annotationType reflect.Type) map[string]annotation.Annotation } // Registry is struct type Registry struct { definitionByType map[reflect.Type]*TypeDefinition definitionByName map[string]*TypeDefinition instanceByType map[reflect.Type]interface{} resourceByName map[string]interface{} } var registry Regist func newRegistry() Regist { r := &Registry{} 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 } // RegisterType is function func RegisterType(t reflect.Type) { pc, _, _, ok := runtime.Caller(1) details := runtime.FuncForPC(pc) if ok && details != nil { log.Printf("called from %s", details.Name()) } registry.RegisterType(t) } func (r *Registry) RegisterType(t reflect.Type) { if nil == t { log.Panicf("DI: t[reflect.Type] is nil") } if !luReflect.IsTypeKind(t, reflect.Struct, true) { log.Panicf("DI: t[reflect.Type] must be specified but is %v", t) } td, err := r.buildDefinition(t) if nil != err { log.Panicf("DI: %v", err) } if _, ok := r.definitionByType[td.Type]; ok { log.Panicf("DI: The type[%s] of Component is exist already", td.FullName) } r.definitionByType[td.Type] = td name := td.TypeName if a := td.GetTypeAnnotationByType(ComponentAnnotationType, true); nil != a { ca := a.(*ComponentAnnotation) if "" != strings.Trim(ca.Name, " ") { name = ca.Name } } if eTD, ok := r.definitionByName[name]; ok { log.Panicf("DI: The name[%s] of Component is exist already type[%s]", name, eTD.FullName) } r.definitionByName[name] = td } func RegisterResource(name string, resource interface{}) error { return registry.RegisterResource(name, resource) } func (r *Registry) RegisterResource(name string, resource interface{}) error { if _, ok := r.resourceByName[name]; ok { return fmt.Errorf("DI: Resource[%s] is already exist", name) } r.resourceByName[name] = resource return nil } // GetInstance returns instance of type // t must be pointer of struct func GetInstance(t reflect.Type) (interface{}, error) { return registry.GetInstance(t) } func (r *Registry) GetInstance(t reflect.Type) (instance interface{}, err error) { if nil == t { 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 ( td *TypeDefinition comV interface{} ok bool ) rt, _, _ := luReflect.GetTypeInfo(t) if td, ok = r.definitionByType[t]; !ok { if td, err = r.buildDefinition(t); nil != err { return nil, fmt.Errorf("DI: %v", err) } } if comV, ok = r.instanceByType[td.RealType]; ok { return comV, nil } v := reflect.New(rt) rv := v.Elem() instance = v.Interface() r.instanceByType[td.RealType] = instance err = nil defer func() { if nil != err { instance = nil delete(r.instanceByType, td.RealType) } }() var ( annotation annotation.Annotation fV interface{} ) for _, fd := range td.Fields { f := rv.FieldByName(fd.FieldName) if !f.IsValid() { err = fmt.Errorf("DI: Field[%s] is not valid", fd.FieldName) return } if !f.CanSet() { err = fmt.Errorf("DI: Field[%s] can not set", fd.FieldName) return } if annotation = fd.GetAnnotationByType(InjectAnnotationType, false); nil != annotation { if fV, err = r.GetInstance(fd.Type); nil != err { return } } if annotation = fd.GetAnnotationByType(ResourceAnnotationType, false); nil != annotation { n := annotation.(*ResourceAnnotation).Name if "" == n { n = fd.FieldName } if fV, err = r.GetInstanceByName(n); nil != err { return } } if nil != err { return } f.Set(reflect.ValueOf(fV)) } return } func GetInstanceByName(name string) (interface{}, error) { return registry.GetInstanceByName(name) } func (r *Registry) GetInstanceByName(name string) (interface{}, error) { v, ok := r.resourceByName[name] if ok { return v, nil } td, ok := r.definitionByName[name] if !ok { return nil, fmt.Errorf("DI: Instance[%s] is not exist", name) } v, err := r.GetInstance(td.Type) if nil != err { return nil, fmt.Errorf("DI: Instance[%s] is not exist -> %s", name, err.Error()) } return v, nil } // GetInstances returns instance of annotated // n must be name of registered annotation func GetInstances(ts []reflect.Type) ([]interface{}, error) { return registry.GetInstances(ts) } func (r *Registry) GetInstances(ts []reflect.Type) ([]interface{}, error) { var ( i interface{} err error ) instances := make([]interface{}, 0) for _, t := range ts { if i, err = r.GetInstance(t); nil != err { return nil, err } instances = append(instances, i) } return instances, nil } func GetInstancesByAnnotationType(t reflect.Type) ([]interface{}, error) { return registry.GetInstancesByAnnotationType(t) } func (r *Registry) GetInstancesByAnnotationType(t reflect.Type) ([]interface{}, error) { var ( i interface{} err error ) instances := make([]interface{}, 0) for _, td := range r.definitionByType { if nil != td.GetTypeAnnotationByType(t, true) { if i, err = r.GetInstance(td.Type); nil != err { return nil, err } instances = append(instances, i) } } return instances, nil } func GetTypeAnnotation(instanceType reflect.Type, annotationType reflect.Type) annotation.Annotation { return registry.GetTypeAnnotation(instanceType, annotationType) } func (r *Registry) GetTypeAnnotation(instanceType reflect.Type, annotationType reflect.Type) annotation.Annotation { def, ok := r.definitionByType[instanceType] if !ok { return nil } return def.GetTypeAnnotationByType(annotationType, false) } func GetMethodAnnotation(instanceType reflect.Type, annotationType reflect.Type, methodName string) annotation.Annotation { return registry.GetMethodAnnotation(instanceType, annotationType, methodName) } func (r *Registry) GetMethodAnnotation(instanceType reflect.Type, annotationType reflect.Type, methodName string) annotation.Annotation { def, ok := r.definitionByType[instanceType] if !ok { return nil } return def.GetMethodAnnotationByType(annotationType, methodName) } func GetMethodAnnotations(instanceType reflect.Type, annotationType reflect.Type) map[string]annotation.Annotation { return registry.GetMethodAnnotations(instanceType, annotationType) } func (r *Registry) GetMethodAnnotations(instanceType reflect.Type, annotationType reflect.Type) map[string]annotation.Annotation { def, ok := r.definitionByType[instanceType] if !ok { return nil } return def.GetMethodAnnotationsByType(annotationType) } func (r *Registry) buildDefinition(t reflect.Type) (*TypeDefinition, error) { if nil == t { return nil, fmt.Errorf("t[reflect.Type] is nil") } rt, pkgName, tName := luReflect.GetTypeInfo(t) td := &TypeDefinition{} td.FullName = FullName(pkgName, tName) td.PkgName = pkgName td.TypeName = tName td.Type = t td.RealType = rt td.Fields = make([]*FieldDefinition, 0) parseFields(rt, td) return td, nil } func parseFields(t reflect.Type, td *TypeDefinition) { // fields := make([]*FieldDefinition, 0) rt, _, _ := luReflect.GetTypeInfo(t) if reflect.Struct != rt.Kind() { return } for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) if f.Anonymous { if parseAnonymousField(&f, td) { continue } parseFields(f.Type, td) } else { if parseMethodAnnotation(&f, td) { continue } as, err := annotation.Parse(f.Tag) if nil != err { return } if nil != as && 0 < len(as) { fRT, fPkgName, fTName := luReflect.GetTypeInfo(f.Type) fd := &FieldDefinition{ FieldName: f.Name, PkgName: fPkgName, TypeName: fTName, Type: f.Type, RealType: fRT, Annotations: as, } td.Fields = append(td.Fields, fd) } } } } func parseAnonymousField(f *reflect.StructField, td *TypeDefinition) bool { if parseTypeAnnotation(f, td) { return true } return false } func parseTypeAnnotation(f *reflect.StructField, td *TypeDefinition) bool { // if !haveEmbeddingOf(cda.TypeAnnotationType, f.Type) { // return // } if annotation.TypeAnnotationType != f.Type { return false } as, err := annotation.Parse(f.Tag) if nil != err { return false } if nil != as && 0 < len(as) { td.TypeAnnotations = as return true } return false } func parseMethodAnnotation(f *reflect.StructField, td *TypeDefinition) bool { if annotation.MethodAnnotationType != f.Type { return false } as, err := annotation.Parse(f.Tag) if nil != err { return false } if nil != as && 0 < len(as) { if nil == td.MethodAnnotations { td.MethodAnnotations = make(map[string]map[reflect.Type]annotation.Annotation, 0) } td.MethodAnnotations[f.Name[1:]] = as return true } return false } func haveEmbeddingOf(t reflect.Type, target reflect.Type) bool { if t == target { return true } rt, _, _ := luReflect.GetTypeInfo(target) if reflect.Struct != rt.Kind() { return false } for i := 0; i < rt.NumField(); i++ { f := rt.Field(i) if f.Anonymous { if haveEmbeddingOf(t, f.Type) { return true } } } return false }