Skip to content

Commit

Permalink
Merge pull request #1 from tiendc/fix-bug-go1-18-have-no-TypeFor
Browse files Browse the repository at this point in the history
Fix bug: Go 1.18 have no reflect.TypeFor function
  • Loading branch information
tiendc authored Sep 4, 2024
2 parents cd1e83e + 26f591e commit 2679a0a
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 51 deletions.
9 changes: 4 additions & 5 deletions autowire.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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]())
}
51 changes: 25 additions & 26 deletions container_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package autowire

import (
"context"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -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'")
Expand All @@ -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'")
Expand All @@ -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'")
Expand All @@ -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")
})
Expand All @@ -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'")
Expand All @@ -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'")
Expand All @@ -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'")
Expand All @@ -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())
Expand All @@ -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()))
})
Expand All @@ -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))
})
Expand All @@ -129,24 +128,24 @@ 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))
})

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())
Expand All @@ -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())
Expand Down
15 changes: 7 additions & 8 deletions container_resolve_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package autowire

import (
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -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))
})
}
8 changes: 4 additions & 4 deletions container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,20 @@ 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'")
})

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)
})
}
2 changes: 1 addition & 1 deletion func_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
})
}
2 changes: 1 addition & 1 deletion provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 2 additions & 3 deletions struct_provider_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package autowire

import (
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -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)
})
Expand Down
8 changes: 8 additions & 0 deletions util.go
Original file line number Diff line number Diff line change
@@ -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()
}
2 changes: 1 addition & 1 deletion value_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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](),
}
}
4 changes: 2 additions & 2 deletions value_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ 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()))
})

t.Run("Success with pointer type", func(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()))
})
}

0 comments on commit 2679a0a

Please sign in to comment.