From d429e10c26c96bc68f8d5fa02cb883ae3b25e379 Mon Sep 17 00:00:00 2001 From: Viktor Stanchev Date: Wed, 19 Nov 2025 07:54:27 +0000 Subject: [PATCH] fix: respect Binder interface for primitive types in BindStringToObject MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the Binder interface was only checked within the struct case of the type switch, causing primitive types (strings, ints, etc.) that implement Binder to bypass their custom binding logic. This fix moves the Binder check to the beginning of BindStringToObject, ensuring all types implementing Binder use their custom Bind method, regardless of their underlying type. The redundant check in the struct case has been removed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- bindstring.go | 10 +++++----- bindstring_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/bindstring.go b/bindstring.go index 764036d..28ba58a 100644 --- a/bindstring.go +++ b/bindstring.go @@ -33,6 +33,11 @@ import ( func BindStringToObject(src string, dst interface{}) error { var err error + // Check if the destination implements Binder interface before any reflection + if binder, ok := dst.(Binder); ok { + return binder.Bind(src) + } + v := reflect.ValueOf(dst) t := reflect.TypeOf(dst) @@ -107,11 +112,6 @@ func BindStringToObject(src string, dst interface{}) error { } fallthrough case reflect.Struct: - // if this is not of type Time or of type Date look to see if this is of type Binder. - if dstType, ok := dst.(Binder); ok { - return dstType.Bind(src) - } - if t.ConvertibleTo(reflect.TypeOf(time.Time{})) { // Don't fail on empty string. if src == "" { diff --git a/bindstring_test.go b/bindstring_test.go index d3c4909..f695db1 100644 --- a/bindstring_test.go +++ b/bindstring_test.go @@ -24,6 +24,16 @@ import ( "github.com/oapi-codegen/runtime/types" ) +// CustomStringBinder is a string type that implements Binder but not TextUnmarshaler +// This tests that Binder interface is checked for primitive types +type CustomStringBinder string + +func (c *CustomStringBinder) Bind(src string) error { + // Custom binding logic: add a prefix to demonstrate the Bind method was called + *c = CustomStringBinder("CUSTOM:" + src) + return nil +} + func TestBindStringToObject(t *testing.T) { var i int assert.NoError(t, BindStringToObject("5", &i)) @@ -209,4 +219,10 @@ func TestBindStringToObject(t *testing.T) { assert.NoError(t, BindStringToObject(uuidString, &dstUUID)) assert.Equal(t, dstUUID.String(), uuidString) + // Checks that primitive types implementing Binder are respected + // This tests the fix for ensuring Binder is checked before type reflection + var customString CustomStringBinder + assert.NoError(t, BindStringToObject("hello", &customString)) + assert.Equal(t, CustomStringBinder("CUSTOM:hello"), customString) + }