Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix bug: Go 1.18 have no reflect.TypeFor function #1

Merged
merged 1 commit into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()))
})
}
Loading