Skip to content

Commit

Permalink
feat(depinject): silently ignore private fields on In structs (#22438)
Browse files Browse the repository at this point in the history
Co-authored-by: Julien Robert <[email protected]>
  • Loading branch information
kocubinski and julienrbrt authored Nov 6, 2024
1 parent 1539e00 commit bf8c0da
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 6 deletions.
4 changes: 4 additions & 0 deletions depinject/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ Each entry must include the Github issue reference in the following format:

## [Unreleased]

## 1.1.0

* [#22438](https://github.com/cosmos/cosmos-sdk/pull/22438) Unexported fields on `In` structs are now silently ignored instead of failing.

## 1.0.0

* [#20540](https://github.com/cosmos/cosmos-sdk/pull/20540) Add support for defining `appconfig` module configuration types using `github.com/cosmos/gogoproto/proto` in addition to `google.golang.org/protobuf` so that users can use gogo proto across their stack.
Expand Down
13 changes: 13 additions & 0 deletions depinject/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,3 +300,16 @@ func TestBindingInterfaceTwoModuleScopedAndGlobalBinding(t *testing.T) {
IsResolvedModuleScope(t, pond, moduleC, "Marbled")
IsResolvedInGlobalScope(t, pond, "Marbled")
}

func TestIgnoredField(t *testing.T) {
t.Parallel()
cfg := struct {
depinject.In
TheDuck Duck
privateField bool
AnotherDuck Duck
}{}

err := depinject.Inject(depinject.Provide(ProvideMallard), &cfg)
require.NoError(t, err)
}
3 changes: 3 additions & 0 deletions depinject/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func (c *container) call(provider *providerDescriptor, moduleKey *moduleKey) ([]
c.indentLogger()
inVals := make([]reflect.Value, len(provider.Inputs))
for i, in := range provider.Inputs {
if in.Ignored {
continue
}
val, err := c.resolve(in, moduleKey, loc)
if err != nil {
return nil, err
Expand Down
3 changes: 1 addition & 2 deletions depinject/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,15 +213,14 @@ func TestUnexportedField(t *testing.T) {
"depinject.Out struct",
)

require.ErrorContains(t,
require.NoError(t,
depinject.Inject(
scenarioConfigDependency,
&handlers,
&commands,
&a,
&c,
),
"depinject.In struct",
)

require.ErrorContains(t,
Expand Down
1 change: 1 addition & 0 deletions depinject/provider_desc.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type providerDescriptor struct {
type providerInput struct {
Type reflect.Type
Optional bool
Ignored bool
}

type providerOutput struct {
Expand Down
11 changes: 7 additions & 4 deletions depinject/struct_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
// In can be embedded in another struct to inform the container that the
// fields of the struct should be treated as dependency inputs.
// This allows a struct to be used to specify dependencies rather than
// positional parameters.
// positional parameters. Unexpected fields will be ignored.
//
// Fields of the struct may support the following tags:
//
Expand Down Expand Up @@ -126,6 +126,7 @@ func structArgsInTypes(typ reflect.Type) ([]providerInput, error) {
res = append(res, providerInput{
Type: f.Type,
Optional: optional,
Ignored: !f.IsExported(),
})
}
return res, nil
Expand Down Expand Up @@ -166,13 +167,15 @@ func buildIn(typ reflect.Type, values []reflect.Value) (reflect.Value, int, erro
j := 0
res := reflect.New(typ)
for i := 0; i < numFields; i++ {
if !res.Elem().Field(i).CanSet() {
// private field, skip
j++
continue
}
f := typ.Field(i)
if f.Type.AssignableTo(isInType) {
continue
}
if !res.Elem().Field(i).CanSet() {
return reflect.Value{}, 0, fmt.Errorf("depinject.In struct %s on package %s can't have unexported field", res.Elem().String(), f.PkgPath)
}
if !values[j].CanInterface() {
return reflect.Value{}, 0, fmt.Errorf("depinject.Out struct %s on package %s can't have unexported field", res.Elem().String(), f.PkgPath)
}
Expand Down

0 comments on commit bf8c0da

Please sign in to comment.