This commit is contained in:
crusader 2017-12-05 22:28:42 +09:00
parent 274c05cbf0
commit 4a4e7cdfdd
10 changed files with 324 additions and 16 deletions

80
annotation/annotation.go Normal file
View File

@ -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
}

View File

@ -1,5 +1,39 @@
package annotation package annotation
// @Inject(name? string)
import (
"strings"
)
const (
InjectTag = "@Inject"
)
type Inject struct { type Inject struct {
Annotation
Name string 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
}

30
annotation/inject_test.go Normal file
View File

@ -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)
}

View File

@ -1,5 +1,35 @@
package annotation package annotation
import "strings"
const (
ResourceTag = "@Resource"
)
type Resource struct { type Resource struct {
Annotation
Name string 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
}

View File

@ -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)
}

View File

@ -23,3 +23,7 @@ const (
ScopeTypeSingleton ScopeTypeSingleton
ScopeTypeTransiant ScopeTypeTransiant
) )
const (
AnnotationTag = "annotation"
)

View File

@ -1,10 +1,25 @@
package registry package registry
import "reflect" import (
"reflect"
type ComponentDefinition struct { cda "git.loafle.net/commons_go/di/annotation"
)
type TypeDefinition struct {
PkgName string PkgName string
TypeName string TypeName string
Type reflect.Type Type reflect.Type
RealType 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
} }

View File

@ -2,26 +2,43 @@ package registry
import ( import (
"fmt" "fmt"
"log"
"reflect" "reflect"
cda "git.loafle.net/commons_go/di/annotation" cda "git.loafle.net/commons_go/di/annotation"
cdur "git.loafle.net/commons_go/di/util/reflect" cdur "git.loafle.net/commons_go/di/util/reflect"
) )
func init() {
registry = newRegistry()
}
var registry ComponentRegistry
type ComponentRegistry interface { type ComponentRegistry interface {
RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error
RegisterFactory(i interface{}, ca *cda.ComponentAnnotation) error
GetInstance(t reflect.Type) (interface{}, error) GetInstance(t reflect.Type) (interface{}, error)
GetInstanceByName(name string) (interface{}, error) GetInstanceByName(name string) (interface{}, error)
} }
type defaultComponentRegistry struct { func newRegistry() ComponentRegistry {
definitionsByType map[reflect.Type]*ComponentDefinition 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 { func (cr *defaultComponentRegistry) RegisterType(t reflect.Type, ca *cda.ComponentAnnotation) error {
if nil == t { if nil == t {
return fmt.Errorf("DI: t[reflect.Type] is nil") 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) return fmt.Errorf("DI: t[reflect.Type] must be specified but is %v", t)
} }
rt, pkgName, tName := cdur.GetTypeName(t) td, err := cr.buildDefinition(t)
cr.definitions[name] = rt 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 return nil
} }
func GetInstance(t reflect.Type) (interface{}, error) {
return registry.GetInstance(t)
}
func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, error) { func (cr *defaultComponentRegistry) GetInstance(t reflect.Type) (interface{}, error) {
if nil == t { if nil == t {
return nil, fmt.Errorf("DI: t[reflect.Type] is nil") return nil, fmt.Errorf("DI: t[reflect.Type] is nil")
} }
var err error
cd, ok := cr.definitionsByType[t] cd, ok := cr.definitionsByType[t]
if !ok { if !ok {
cd = cr.buildDefinition(t) cd, err = cr.buildDefinition(t)
if nil != err {
return nil, err
}
} }
log.Printf("%v", cd)
return nil, nil return nil, nil
} }
func GetInstanceByName(name string) (interface{}, error) {
return registry.GetInstanceByName(name)
}
func (cr *defaultComponentRegistry) GetInstanceByName(name string) (interface{}, error) { func (cr *defaultComponentRegistry) GetInstanceByName(name string) (interface{}, error) {
return nil, nil return nil, nil
} }
func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*ComponentDefinition, error) { func (cr *defaultComponentRegistry) buildDefinition(t reflect.Type) (*TypeDefinition, error) {
if nil == t { if nil == t {
return nil, fmt.Errorf("DI: t[reflect.Type] is nil") return nil, fmt.Errorf("DI: t[reflect.Type] is nil")
} }
rt, pkgName, tName := cdur.GetTypeName(t) rt, pkgName, tName := cdur.GetTypeInfo(t)
cd := &ComponentDefinition{} cd := &TypeDefinition{}
cd.PkgName = pkgName cd.PkgName = pkgName
cd.TypeName = tName cd.TypeName = tName
cd.Type = t cd.Type = t
cd.RealType = rt 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
} }

18
registry/registry_test.go Normal file
View File

@ -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)"`
}

View File

@ -14,9 +14,9 @@ func IsTypeKind(t reflect.Type, kind reflect.Kind, removePtr bool) bool {
return kind == t.Kind() 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() { if reflect.Ptr == t.Kind() {
return GetTypeName(t.Elem()) return GetTypeInfo(t.Elem())
} }
return t, t.PkgPath(), t.Name() return t, t.PkgPath(), t.Name()