From 26f591ef959ab3c48a9570e03f8e62a7c3d3911b Mon Sep 17 00:00:00 2001 From: tiendc Date: Wed, 4 Sep 2024 18:24:12 +0700 Subject: [PATCH] Fix bug: Go 1.18 have no reflect.TypeFor function --- autowire.go | 9 +++---- container_build_test.go | 51 +++++++++++++++++++-------------------- container_resolve_test.go | 15 ++++++------ container_test.go | 8 +++--- func_provider_test.go | 2 +- provider.go | 2 +- struct_provider_test.go | 5 ++-- util.go | 8 ++++++ value_provider.go | 2 +- value_provider_test.go | 4 +-- 10 files changed, 55 insertions(+), 51 deletions(-) create mode 100644 util.go diff --git a/autowire.go b/autowire.go index 1df406f..500506e 100644 --- a/autowire.go +++ b/autowire.go @@ -3,12 +3,11 @@ package autowire import ( "context" "fmt" - "reflect" ) // Build builds object for the specified type within a container func Build[T any](c Container, opts ...ContextOption) (value T, err error) { - targetType := reflect.TypeFor[T]() + targetType := typeFor[T]() val, err := c.Build(targetType, opts...) if err != nil { @@ -26,7 +25,7 @@ func Build[T any](c Container, opts ...ContextOption) (value T, err error) { // BuildWithCtx builds object for the specified type within a container. // This function will pass the specified context object to every provider that requires a context. func BuildWithCtx[T any](ctx context.Context, c Container, opts ...ContextOption) (value T, err error) { - targetType := reflect.TypeFor[T]() + targetType := typeFor[T]() val, err := c.BuildWithCtx(ctx, targetType, opts...) if err != nil { @@ -44,7 +43,7 @@ func BuildWithCtx[T any](ctx context.Context, c Container, opts ...ContextOption // Get gets object of a type within a container. // If no object is created for the type or `sharedMode` is `false`, ErrNotFound is returned. func Get[T any](c Container) (value T, err error) { - targetType := reflect.TypeFor[T]() + targetType := typeFor[T]() val, err := c.Get(targetType) if err != nil { @@ -61,5 +60,5 @@ func Get[T any](c Container) (value T, err error) { // Resolve builds dependency graph for the specified type within a container func Resolve[T any](c Container) (DependencyGraph, error) { - return c.Resolve(reflect.TypeFor[T]()) + return c.Resolve(typeFor[T]()) } diff --git a/container_build_test.go b/container_build_test.go index ab1810f..df7b135 100644 --- a/container_build_test.go +++ b/container_build_test.go @@ -2,7 +2,6 @@ package autowire import ( "context" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -18,7 +17,7 @@ func TestContainerBuild_Failure(t *testing.T) { t.Run("Provider not found (user type)", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3, NewSrv2_OK}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, ErrNotFound) assert.Contains(t, err.Error(), "ErrNotFound: provider not found for type 'autowire.Service3'") @@ -27,7 +26,7 @@ func TestContainerBuild_Failure(t *testing.T) { t.Run("Provider not found (primitive type)", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_Struct1, NewSrv2_OK, NewSrv3_OK}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, ErrNotFound) assert.Contains(t, err.Error(), "ErrNotFound: provider not found for type '*autowire.Struct1_OK'") @@ -36,7 +35,7 @@ func TestContainerBuild_Failure(t *testing.T) { t.Run("Provider not found for target type", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK, NewSrv2_OK}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service3]()) + _, err = c.Build(typeFor[Service3]()) assert.ErrorIs(t, err, ErrNotFound) assert.Contains(t, err.Error(), "ErrNotFound: provider not found for type 'autowire.Service3'") @@ -45,7 +44,7 @@ func TestContainerBuild_Failure(t *testing.T) { t.Run("Provider return error as 2nd value", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_Fail_With_Err, NewSrv2_OK, NewSrv3_OK}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, errTest1) assert.Contains(t, err.Error(), "errTest1") }) @@ -55,7 +54,7 @@ func TestContainerBuild_Failure(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3, NewSrv2_OK_With_Need_Srv4_Srv5, NewSrv5_OK, NewSrv3_OK, NewSrv4_OK_With_Need_Srv1}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, ErrCircularDependency) assert.Contains(t, err.Error(), "ErrCircularDependency: circular dependency detected at type 'autowire.Service1'") @@ -65,7 +64,7 @@ func TestContainerBuild_Failure(t *testing.T) { // S1 -> S1 c, err := NewContainer([]any{NewSrv1_Fail_Need_Srv1}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, ErrCircularDependency) assert.Contains(t, err.Error(), "ErrCircularDependency: circular dependency detected at type 'autowire.Service1'") @@ -74,7 +73,7 @@ func TestContainerBuild_Failure(t *testing.T) { t.Run("Requires context.Context, but not provide", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Ctx}) assert.Nil(t, err) - _, err = c.Build(reflect.TypeFor[Service1]()) + _, err = c.Build(typeFor[Service1]()) assert.ErrorIs(t, err, ErrNotFound) assert.Contains(t, err.Error(), "ErrNotFound: provider not found for type 'context.Context'") @@ -86,11 +85,11 @@ func TestContainerBuild_Success(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_IntSlice, NewSrv2_OK_With_Need_Srv4_Srv5, NewSrv3_OK, NewSrv4_OK, NewSrv5_OK, &struct1_OK, &struct5_OK}) assert.Nil(t, err) - s1, err := c.Build(reflect.TypeFor[Service1]()) + s1, err := c.Build(typeFor[Service1]()) assert.Nil(t, err) - s2, err := c.Get(reflect.TypeFor[Service2]()) + s2, err := c.Get(typeFor[Service2]()) assert.Nil(t, err) - s3, err := c.Get(reflect.TypeFor[Service3]()) + s3, err := c.Get(typeFor[Service3]()) assert.Nil(t, err) assert.Equal(t, []any{s2.Interface().(Service2), s3.Interface().(Service3), struct1_OK.Slice}, s1.Interface().(Service1).InitArgs()) @@ -100,13 +99,13 @@ func TestContainerBuild_Success(t *testing.T) { ctx := context.Background() c, err := NewContainer([]any{NewSrv1_OK_With_Need_Ctx, NewSrv4_OK, NewSrv5_OK, &struct1_OK}) assert.Nil(t, err) - s1, err := c.BuildWithCtx(ctx, reflect.TypeFor[Service1]()) + s1, err := c.BuildWithCtx(ctx, typeFor[Service1]()) assert.Nil(t, err) assert.Equal(t, []any{ctx}, s1.Interface().(Service1).InitArgs()) - s4, err := c.Build(reflect.TypeFor[Service4]()) + s4, err := c.Build(typeFor[Service4]()) assert.Nil(t, err) assert.Equal(t, 0, len(s4.Interface().(Service4).InitArgs())) - s5, err := c.Build(reflect.TypeFor[Service5]()) + s5, err := c.Build(typeFor[Service5]()) assert.Nil(t, err) assert.Equal(t, 0, len(s5.Interface().(Service5).InitArgs())) }) @@ -115,12 +114,12 @@ func TestContainerBuild_Success(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_IntSlice, NewSrv2_OK_With_Need_Srv4_Srv5, NewSrv3_OK, NewSrv4_OK, NewSrv5_OK, &struct1_OK, &struct5_OK}, SetSharedMode(false)) assert.Nil(t, err) - s1, err := c.Build(reflect.TypeFor[Service1]()) + s1, err := c.Build(typeFor[Service1]()) assert.Nil(t, err) assert.NotNil(t, s1.Interface().(Service1)) - _, err = c.Get(reflect.TypeFor[Service2]()) + _, err = c.Get(typeFor[Service2]()) assert.ErrorIs(t, err, ErrNotFound) - s2, err := c.Build(reflect.TypeFor[Service2]()) + s2, err := c.Build(typeFor[Service2]()) assert.Nil(t, err) assert.NotNil(t, s2.Interface().(Service2)) }) @@ -129,12 +128,12 @@ func TestContainerBuild_Success(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_IntSlice, NewSrv2_OK_With_Need_Srv4_Srv5, NewSrv3_OK, NewSrv4_OK, NewSrv5_OK, &struct1_OK, &struct5_OK}) assert.Nil(t, err) - s1, err := c.Build(reflect.TypeFor[Service1](), NonSharedMode()) + s1, err := c.Build(typeFor[Service1](), NonSharedMode()) assert.Nil(t, err) assert.NotNil(t, s1.Interface().(Service1)) - _, err = c.Get(reflect.TypeFor[Service2]()) + _, err = c.Get(typeFor[Service2]()) assert.ErrorIs(t, err, ErrNotFound) - s2, err := c.Build(reflect.TypeFor[Service2](), NonSharedMode()) + s2, err := c.Build(typeFor[Service2](), NonSharedMode()) assert.Nil(t, err) assert.NotNil(t, s2.Interface().(Service2)) }) @@ -142,11 +141,11 @@ func TestContainerBuild_Success(t *testing.T) { t.Run("Success, with overwriting type []int", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_IntSlice, NewSrv2_OK, NewSrv3_OK, &struct1_OK}) assert.Nil(t, err) - s1, err := c.Build(reflect.TypeFor[Service1](), ProviderOverwrite([]int{1, 1})) + s1, err := c.Build(typeFor[Service1](), ProviderOverwrite([]int{1, 1})) assert.Nil(t, err) - s2, err := c.Get(reflect.TypeFor[Service2]()) + s2, err := c.Get(typeFor[Service2]()) assert.Nil(t, err) - s3, err := c.Get(reflect.TypeFor[Service3]()) + s3, err := c.Get(typeFor[Service3]()) assert.Nil(t, err) assert.Equal(t, []any{s2.Interface().(Service2), s3.Interface().(Service3), []int{1, 1}}, s1.Interface().(Service1).InitArgs()) @@ -160,11 +159,11 @@ func TestContainerBuild_Success(t *testing.T) { // Update struct field value struct1Copy.Slice = []int{100, 200} - s1, err := c.Build(reflect.TypeFor[Service1]()) + s1, err := c.Build(typeFor[Service1]()) assert.Nil(t, err) - s2, err := c.Get(reflect.TypeFor[Service2]()) + s2, err := c.Get(typeFor[Service2]()) assert.Nil(t, err) - s3, err := c.Get(reflect.TypeFor[Service3]()) + s3, err := c.Get(typeFor[Service3]()) assert.Nil(t, err) assert.Equal(t, []any{s2.Interface().(Service2), s3.Interface().(Service3), []int{100, 200}}, s1.Interface().(Service1).InitArgs()) diff --git a/container_resolve_test.go b/container_resolve_test.go index b762231..332c5df 100644 --- a/container_resolve_test.go +++ b/container_resolve_test.go @@ -1,7 +1,6 @@ package autowire import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -71,27 +70,27 @@ func TestContainerResolve_Success(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK_With_Need_Srv2_Srv3_IntSlice, NewSrv2_OK_With_Need_Srv4_Srv5, NewSrv3_OK, NewSrv4_OK, NewSrv5_OK, &struct1_OK, &struct5_OK}) assert.Nil(t, err) - dg, err := c.Resolve(reflect.TypeFor[Service1]()) + dg, err := c.Resolve(typeFor[Service1]()) assert.Nil(t, err) - assert.Equal(t, reflect.TypeFor[Service1](), dg.TargetType) + assert.Equal(t, typeFor[Service1](), dg.TargetType) assert.Equal(t, 3, len(dg.Dependencies)) dg1 := dg.Dependencies[0] - assert.Equal(t, reflect.TypeFor[Service2](), dg1.TargetType) + assert.Equal(t, typeFor[Service2](), dg1.TargetType) assert.Equal(t, 2, len(dg1.Dependencies)) dg11 := dg1.Dependencies[0] - assert.Equal(t, reflect.TypeFor[Service4](), dg11.TargetType) + assert.Equal(t, typeFor[Service4](), dg11.TargetType) assert.Equal(t, 0, len(dg11.Dependencies)) dg12 := dg1.Dependencies[1] - assert.Equal(t, reflect.TypeFor[Service5](), dg12.TargetType) + assert.Equal(t, typeFor[Service5](), dg12.TargetType) assert.Equal(t, 0, len(dg12.Dependencies)) dg2 := dg.Dependencies[1] - assert.Equal(t, reflect.TypeFor[Service3](), dg2.TargetType) + assert.Equal(t, typeFor[Service3](), dg2.TargetType) assert.Equal(t, 0, len(dg2.Dependencies)) dg3 := dg.Dependencies[2] - assert.Equal(t, reflect.TypeFor[[]int](), dg3.TargetType) + assert.Equal(t, typeFor[[]int](), dg3.TargetType) assert.Equal(t, 0, len(dg3.Dependencies)) }) } diff --git a/container_test.go b/container_test.go index 411b518..9cdb5d6 100644 --- a/container_test.go +++ b/container_test.go @@ -48,7 +48,7 @@ func TestContainerGet(t *testing.T) { t.Run("Not found", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK}) assert.Nil(t, err) - _, err = c.Get(reflect.TypeFor[Service1]()) + _, err = c.Get(typeFor[Service1]()) assert.ErrorIs(t, err, ErrNotFound) assert.Contains(t, err.Error(), "ErrNotFound: object not found for type 'autowire.Service1'") }) @@ -56,12 +56,12 @@ func TestContainerGet(t *testing.T) { t.Run("Success", func(t *testing.T) { c, err := NewContainer([]any{NewSrv1_OK}) assert.Nil(t, err) - v1, err := c.Build(reflect.TypeFor[Service1]()) + v1, err := c.Build(typeFor[Service1]()) assert.Nil(t, err) - v2, err := c.Get(reflect.TypeFor[Service1]()) + v2, err := c.Get(typeFor[Service1]()) assert.Nil(t, err) assert.Equal(t, v1, v2) - _, err = c.Get(reflect.TypeFor[Service2]()) + _, err = c.Get(typeFor[Service2]()) assert.ErrorIs(t, err, ErrNotFound) }) } diff --git a/func_provider_test.go b/func_provider_test.go index 14f583d..bd80f26 100644 --- a/func_provider_test.go +++ b/func_provider_test.go @@ -56,7 +56,7 @@ func TestFuncProvider_Success(t *testing.T) { ps1, err := parseProviders(NewSrv1_OK) assert.Nil(t, err) assert.Equal(t, 1, len(ps1.GetAll())) - assert.Equal(t, reflect.TypeFor[Service1](), ps1.GetAll()[0].TargetTypes()[0]) + assert.Equal(t, typeFor[Service1](), ps1.GetAll()[0].TargetTypes()[0]) assert.Equal(t, reflect.TypeOf(NewSrv1_OK), reflect.TypeOf(ps1.GetAll()[0].Source())) }) } diff --git a/provider.go b/provider.go index 0935207..e2c2599 100644 --- a/provider.go +++ b/provider.go @@ -5,7 +5,7 @@ import ( ) var ( - typeError = reflect.TypeFor[error]() + typeError = typeFor[error]() ) // Provider a provider is an `object creator` and provide the object to a container. diff --git a/struct_provider_test.go b/struct_provider_test.go index 4d23e6a..37ebc3e 100644 --- a/struct_provider_test.go +++ b/struct_provider_test.go @@ -1,7 +1,6 @@ package autowire import ( - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -58,10 +57,10 @@ func TestStructProvider_Success(t *testing.T) { ps1, err := parseProviders(&struct7_OK_Nested) assert.Nil(t, err) assert.Equal(t, 7, len(ps1.GetAll())) // 5 fields and 2 nested structs themselves - prov1, err := ps1.GetFor(reflect.TypeFor[Nested1]()) + prov1, err := ps1.GetFor(typeFor[Nested1]()) assert.Nil(t, err) assert.Equal(t, prov1.Source(), &struct7_OK_Nested) - prov2, err := ps1.GetFor(reflect.TypeFor[*Nested2]()) + prov2, err := ps1.GetFor(typeFor[*Nested2]()) assert.Nil(t, err) assert.Equal(t, prov2.Source(), &struct7_OK_Nested) }) diff --git a/util.go b/util.go new file mode 100644 index 0000000..790e63a --- /dev/null +++ b/util.go @@ -0,0 +1,8 @@ +package autowire + +import "reflect" + +// typeFor returns the [Type] that represents the type argument T. +func typeFor[T any]() reflect.Type { + return reflect.TypeOf((*T)(nil)).Elem() +} diff --git a/value_provider.go b/value_provider.go index 8f4af69..274d4a0 100644 --- a/value_provider.go +++ b/value_provider.go @@ -29,6 +29,6 @@ func (p *valueProvider) Build(ctx *Context, targetType reflect.Type) (reflect.Va func newValueProvider[T any](provSrc T, provVal reflect.Value) *valueProvider { return &valueProvider{ baseProvider: baseProvider{source: provSrc, sourceVal: provVal}, - targetType: reflect.TypeFor[T](), + targetType: typeFor[T](), } } diff --git a/value_provider_test.go b/value_provider_test.go index cf8e04c..952b7c8 100644 --- a/value_provider_test.go +++ b/value_provider_test.go @@ -11,7 +11,7 @@ func TestValueProvider(t *testing.T) { t.Run("Success with primitive type", func(t *testing.T) { p := newValueProvider(123, reflect.ValueOf(123)) assert.Equal(t, 1, len(p.TargetTypes())) - assert.Equal(t, reflect.TypeFor[int](), p.TargetTypes()[0]) + assert.Equal(t, typeFor[int](), p.TargetTypes()[0]) assert.Equal(t, 0, len(p.DependentTypes())) }) @@ -19,7 +19,7 @@ func TestValueProvider(t *testing.T) { v := "abc" p := newValueProvider(&v, reflect.ValueOf(&v)) assert.Equal(t, 1, len(p.TargetTypes())) - assert.Equal(t, reflect.TypeFor[*string](), p.TargetTypes()[0]) + assert.Equal(t, typeFor[*string](), p.TargetTypes()[0]) assert.Equal(t, 0, len(p.DependentTypes())) }) }