This commit is contained in:
crusader 2018-09-04 15:12:06 +09:00
parent 35e3b97fb9
commit 93072d1a5e
7 changed files with 184 additions and 73 deletions

10
Gopkg.lock generated
View File

@ -5,13 +5,19 @@
branch = "master" branch = "master"
name = "git.loafle.net/overflow/annotation-go" name = "git.loafle.net/overflow/annotation-go"
packages = ["."] packages = ["."]
revision = "9d80d778c61e1a08a46c19835e36f18cf08c1f91" revision = "178b12d303bdd83566a35d71cce68b0c6cc1f4d3"
[[projects]] [[projects]]
branch = "master" branch = "master"
name = "git.loafle.net/overflow/util-go" name = "git.loafle.net/overflow/util-go"
packages = ["reflect"] packages = ["reflect"]
revision = "01cc315e25b38331c0a366d8025600ed4e297e8e" revision = "fae2846a85aad314ee44957d428478fbe800045f"
[[projects]]
name = "gopkg.in/yaml.v2"
packages = ["."]
revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
version = "v2.2.1"
[solve-meta] [solve-meta]
analyzer-name = "dep" analyzer-name = "dep"

View File

@ -17,4 +17,5 @@ var InjectAnnotationType = reflect.TypeOf((*InjectAnnotation)(nil))
type InjectAnnotation struct { type InjectAnnotation struct {
oa.Annotation `@name:"@Inject"` oa.Annotation `@name:"@Inject"`
Name string `json:"name" @default:""` Name string `json:"name" @default:""`
Required bool `json:"required" @default:"true"`
} }

View File

@ -17,15 +17,4 @@ var InjectableAnnotationType = reflect.TypeOf((*InjectableAnnotation)(nil))
type InjectableAnnotation struct { type InjectableAnnotation struct {
oa.Annotation `@name:"@Injectable"` oa.Annotation `@name:"@Injectable"`
Name string `json:"name" @default:""` Name string `json:"name" @default:""`
InitMethod string `json:"initMethod"`
DestroyMethod string `json:"destroyMethod"`
Scope ScopeType `json:"scope"`
} }
type ScopeType string
const (
ScopeTypeDefault ScopeType = "Default" // == ScopeTypeSingleton
ScopeTypeSingleton ScopeType = "Singleton"
ScopeTypeTransiant ScopeType = "Transiant"
)

View File

@ -1,20 +0,0 @@
package annotation
// @Resource(name? string)
import (
"reflect"
oa "git.loafle.net/overflow/annotation-go"
)
func init() {
oa.Register(ResourceAnnotationType)
}
var ResourceAnnotationType = reflect.TypeOf((*ResourceAnnotation)(nil))
type ResourceAnnotation struct {
oa.Annotation `@name:"@Resource"`
Name string `json:"name" @default:""`
}

71
annotation/scope.go Normal file
View File

@ -0,0 +1,71 @@
package annotation
// @Scope(name? string)
import (
"encoding/json"
"fmt"
"reflect"
oa "git.loafle.net/overflow/annotation-go"
)
func init() {
oa.Register(ScopeAnnotationType)
}
var ScopeAnnotationType = reflect.TypeOf((*ScopeAnnotation)(nil))
type ScopeAnnotation struct {
oa.Annotation `@name:"@Scope"`
Value ScopeType `json:"value" @default:"singleton"`
}
type ScopeType int8
const (
ScopeTypeDefault ScopeType = iota + 1
ScopeTypeSingleton
ScopeTypeTransiant
)
var (
scopeTypeID = map[ScopeType]string{
ScopeTypeDefault: "default",
ScopeTypeSingleton: "singleton",
ScopeTypeTransiant: "transiant",
}
scopeTypeKey = map[string]ScopeType{
"default": ScopeTypeDefault,
"singleton": ScopeTypeSingleton,
"transiant": ScopeTypeTransiant,
}
)
func (st ScopeType) String() string {
return scopeTypeID[st]
}
func (st ScopeType) MarshalJSON() ([]byte, error) {
value, ok := scopeTypeID[st]
if !ok {
return nil, fmt.Errorf("Invalid EnumType[%s] value", st)
}
return json.Marshal(value)
}
func (st ScopeType) UnmarshalJSON(b []byte) error {
var s string
err := json.Unmarshal(b, &s)
if err != nil {
return err
}
value, ok := scopeTypeKey[s]
if !ok {
return fmt.Errorf("Invalid EnumType[%s] value", s)
}
st = value
return nil
}

View File

@ -13,7 +13,8 @@ import (
type Registry interface { type Registry interface {
RegisterType(t reflect.Type) RegisterType(t reflect.Type)
RegisterResource(name string, resource interface{}) error RegisterSingleton(singleton interface{}) error
RegisterSingletonByName(name string, singleton interface{}) error
GetInstance(t reflect.Type) (interface{}, error) GetInstance(t reflect.Type) (interface{}, error)
GetInstances(ts []reflect.Type) ([]interface{}, error) GetInstances(ts []reflect.Type) ([]interface{}, error)
@ -59,7 +60,7 @@ func (r *InstanceRegistry) RegisterType(t reflect.Type) {
log.Panicf("t[reflect.Type] is nil") log.Panicf("t[reflect.Type] is nil")
} }
if !our.IsTypeKind(t, reflect.Struct, true) { if !our.IsTypeKind(t, reflect.Struct, true) {
log.Panicf("t[reflect.Type] must be specified but is %v", t) log.Panicf("t[reflect.Type] must be Struct but is %v", t)
} }
td, err := r.buildDefinition(t) td, err := r.buildDefinition(t)
@ -91,14 +92,42 @@ func (r *InstanceRegistry) RegisterType(t reflect.Type) {
r.definitionByName[name] = td r.definitionByName[name] = td
} }
func RegisterResource(name string, resource interface{}) error { func RegisterSingleton(singleton interface{}) error {
return AppRegistry.RegisterResource(name, resource) return AppRegistry.RegisterSingleton(singleton)
} }
func (r *InstanceRegistry) RegisterResource(name string, resource interface{}) error { func (r *InstanceRegistry) RegisterSingleton(singleton interface{}) error {
if _, ok := r.instanceByName[name]; ok { t := reflect.TypeOf(singleton)
return fmt.Errorf("Resource[%s] is already exist", name)
if nil == t {
log.Panicf("t[reflect.Type] is nil")
} }
r.instanceByName[name] = resource
rt, _, tName := our.GetTypeInfo(t)
if !our.IsTypeKind(rt, reflect.Struct, true) {
log.Panicf("t[reflect.Type] must be Struct but is %v", t)
}
r.instanceByType[rt] = singleton
r.RegisterSingletonByName(tName, singleton)
return nil
}
func RegisterSingletonByName(name string, singleton interface{}) error {
return AppRegistry.RegisterSingletonByName(name, singleton)
}
func (r *InstanceRegistry) RegisterSingletonByName(name string, singleton interface{}) error {
t := reflect.TypeOf(singleton)
if nil == t {
log.Panicf("t[reflect.Type] is nil")
}
if _, ok := r.instanceByName[name]; ok {
return fmt.Errorf("name[%s] of Singleton is already exist", name)
}
r.instanceByName[name] = singleton
return nil return nil
} }
@ -139,7 +168,7 @@ func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, er
var ( var (
td *TypeDefinition td *TypeDefinition
comV interface{} injectableV interface{}
ok bool ok bool
) )
@ -150,8 +179,8 @@ func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, er
} }
} }
if comV, ok = r.instanceByType[td.RealType]; ok { if injectableV, ok = r.instanceByType[td.RealType]; ok {
return comV, nil return injectableV, nil
} }
v := reflect.New(rt) v := reflect.New(rt)
@ -159,6 +188,14 @@ func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, er
instance = v.Interface() instance = v.Interface()
r.instanceByType[td.RealType] = instance r.instanceByType[td.RealType] = instance
if a, err := oa.GetTypeAnnotation(td.Type, annotation.InjectableAnnotationType); nil == err && nil != a {
_a := a.(*annotation.InjectableAnnotation)
if "" != _a.Name {
r.instanceByName[_a.Name] = instance
}
}
err = nil err = nil
defer func() { defer func() {
if nil != err { if nil != err {
@ -177,6 +214,7 @@ func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, er
return nil, fmt.Errorf("%v", err) return nil, fmt.Errorf("%v", err)
} }
if nil != ass { if nil != ass {
LOOP:
for n, as := range ass { for n, as := range ass {
f := rv.FieldByName(n) f := rv.FieldByName(n)
@ -191,26 +229,47 @@ func (r *InstanceRegistry) GetInstance(t reflect.Type) (instance interface{}, er
a, ok = as[annotation.InjectAnnotationType] a, ok = as[annotation.InjectAnnotationType]
if ok { if ok {
if fV, err = r.GetInstance(f.Type()); nil != err { _a := a.(*annotation.InjectAnnotation)
return if "" == _a.Name {
} if fV, err = r.GetInstance(f.Type()); nil == err {
log.Printf("%s of %s injected by type[%s]", n, td.RealType.Name(), reflect.TypeOf(fV))
f.Set(reflect.ValueOf(fV))
continue LOOP
} else {
err = fmt.Errorf("cannot find instance for %s[Type:%s]", n, f.Type())
} }
a, ok = as[annotation.ResourceAnnotationType] if fV, err = r.GetInstanceByName(n); nil == err {
if ok { log.Printf("%s of %s injected by name[%s]", n, td.RealType.Name(), n)
name := a.(*annotation.ResourceAnnotation).Name f.Set(reflect.ValueOf(fV))
if "" == name { continue LOOP
name = n } else {
err = fmt.Errorf("cannot find instance for %s[Name:%s]", n, n)
} }
if fV, err = r.GetInstanceByName(name); nil != err { } else {
return if fV, err = r.GetInstanceByName(_a.Name); nil == err {
log.Printf("%s of %s injected by name[%s]", n, td.RealType.Name(), _a.Name)
f.Set(reflect.ValueOf(fV))
continue LOOP
} else {
err = fmt.Errorf("cannot find instance for %s[Name:%s]", n, _a.Name)
}
if fV, err = r.GetInstance(f.Type()); nil == err {
log.Printf("%s of %s injected by type[%s]", n, td.RealType.Name(), reflect.TypeOf(fV))
f.Set(reflect.ValueOf(fV))
continue LOOP
} else {
err = fmt.Errorf("cannot find instance for %s[Type:%s]", n, f.Type())
} }
} }
if nil != err { if nil != err {
if _a.Required {
return return
} }
f.Set(reflect.ValueOf(fV)) }
}
} }
} }
@ -221,11 +280,18 @@ func GetInstanceByName(name string) (interface{}, error) {
return AppRegistry.GetInstanceByName(name) return AppRegistry.GetInstanceByName(name)
} }
func (r *InstanceRegistry) GetInstanceByName(name string) (interface{}, error) { func (r *InstanceRegistry) GetInstanceByName(name string) (interface{}, error) {
if td, ok := r.definitionByName[name]; ok {
v, err := r.GetInstance(td.Type)
if nil == err {
return v, nil
}
}
v, ok := r.instanceByName[name] v, ok := r.instanceByName[name]
if ok { if ok {
return v, nil return v, nil
} }
return nil, fmt.Errorf("Resource[%s] is not exist", name) return nil, fmt.Errorf("Instance[%s] is not exist", name)
} }
// GetInstances returns instance of annotated // GetInstances returns instance of annotated

View File

@ -52,7 +52,6 @@ func TestRegisterType(t *testing.T) {
name string name string
args args args args
}{ }{
// TODO: Add test cases.
{ {
name: "InjectableService", name: "InjectableService",
args: args{ args: args{
@ -99,7 +98,7 @@ func TestInstanceRegistry_RegisterType(t *testing.T) {
} }
} }
func TestRegisterResource(t *testing.T) { func TestRegisterSingletonByName(t *testing.T) {
type args struct { type args struct {
name string name string
resource interface{} resource interface{}
@ -113,14 +112,14 @@ func TestRegisterResource(t *testing.T) {
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
if err := RegisterResource(tt.args.name, tt.args.resource); (err != nil) != tt.wantErr { if err := RegisterSingletonByName(tt.args.name, tt.args.resource); (err != nil) != tt.wantErr {
t.Errorf("RegisterResource() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("RegisterSingletonByName() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })
} }
} }
func TestInstanceRegistry_RegisterResource(t *testing.T) { func TestInstanceRegistry_RegisterSingletonByName(t *testing.T) {
type fields struct { type fields struct {
parent Registry parent Registry
definitionByType map[reflect.Type]*TypeDefinition definitionByType map[reflect.Type]*TypeDefinition
@ -149,8 +148,8 @@ func TestInstanceRegistry_RegisterResource(t *testing.T) {
instanceByType: tt.fields.instanceByType, instanceByType: tt.fields.instanceByType,
instanceByName: tt.fields.instanceByName, instanceByName: tt.fields.instanceByName,
} }
if err := r.RegisterResource(tt.args.name, tt.args.resource); (err != nil) != tt.wantErr { if err := r.RegisterSingletonByName(tt.args.name, tt.args.resource); (err != nil) != tt.wantErr {
t.Errorf("InstanceRegistry.RegisterResource() error = %v, wantErr %v", err, tt.wantErr) t.Errorf("InstanceRegistry.RegisterSingletonByName() error = %v, wantErr %v", err, tt.wantErr)
} }
}) })
} }
@ -208,7 +207,6 @@ func TestGetInstance(t *testing.T) {
args args args args
wantErr bool wantErr bool
}{ }{
// TODO: Add test cases.
{ {
name: "InjectService", name: "InjectService",
args: args{ args: args{