mirror of
				https://github.com/labstack/echo.git
				synced 2025-10-30 23:57:38 +02:00 
			
		
		
		
	binder: make binding to Map work better with string destinations (#2554)
This commit is contained in:
		
							
								
								
									
										20
									
								
								bind.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								bind.go
									
									
									
									
									
								
							| @@ -131,10 +131,26 @@ func (b *DefaultBinder) bindData(destination interface{}, data map[string][]stri | ||||
| 	typ := reflect.TypeOf(destination).Elem() | ||||
| 	val := reflect.ValueOf(destination).Elem() | ||||
|  | ||||
| 	// Map | ||||
| 	if typ.Kind() == reflect.Map { | ||||
| 	// Support binding to limited Map destinations: | ||||
| 	// - map[string][]string, | ||||
| 	// - map[string]string <-- (binds first value from data slice) | ||||
| 	// - map[string]interface{} | ||||
| 	// You are better off binding to struct but there are user who want this map feature. Source of data for these cases are: | ||||
| 	// params,query,header,form as these sources produce string values, most of the time slice of strings, actually. | ||||
| 	if typ.Kind() == reflect.Map && typ.Key().Kind() == reflect.String { | ||||
| 		k := typ.Elem().Kind() | ||||
| 		isElemInterface := k == reflect.Interface | ||||
| 		isElemString := k == reflect.String | ||||
| 		isElemSliceOfStrings := k == reflect.Slice && typ.Elem().Elem().Kind() == reflect.String | ||||
| 		if !(isElemSliceOfStrings || isElemString || isElemInterface) { | ||||
| 			return nil | ||||
| 		} | ||||
| 		for k, v := range data { | ||||
| 			if isElemString { | ||||
| 				val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0])) | ||||
| 			} else { | ||||
| 				val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v)) | ||||
| 			} | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
|   | ||||
							
								
								
									
										56
									
								
								bind_test.go
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								bind_test.go
									
									
									
									
									
								
							| @@ -429,6 +429,62 @@ func TestBindUnsupportedMediaType(t *testing.T) { | ||||
| 	testBindError(t, strings.NewReader(invalidContent), MIMEApplicationJSON, &json.SyntaxError{}) | ||||
| } | ||||
|  | ||||
| func TestDefaultBinder_bindDataToMap(t *testing.T) { | ||||
| 	exampleData := map[string][]string{ | ||||
| 		"multiple": {"1", "2"}, | ||||
| 		"single":   {"3"}, | ||||
| 	} | ||||
|  | ||||
| 	t.Run("ok, bind to map[string]string", func(t *testing.T) { | ||||
| 		dest := map[string]string{} | ||||
| 		assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param")) | ||||
| 		assert.Equal(t, | ||||
| 			map[string]string{ | ||||
| 				"multiple": "1", | ||||
| 				"single":   "3", | ||||
| 			}, | ||||
| 			dest, | ||||
| 		) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ok, bind to map[string][]string", func(t *testing.T) { | ||||
| 		dest := map[string][]string{} | ||||
| 		assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param")) | ||||
| 		assert.Equal(t, | ||||
| 			map[string][]string{ | ||||
| 				"multiple": {"1", "2"}, | ||||
| 				"single":   {"3"}, | ||||
| 			}, | ||||
| 			dest, | ||||
| 		) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ok, bind to map[string]interface", func(t *testing.T) { | ||||
| 		dest := map[string]interface{}{} | ||||
| 		assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param")) | ||||
| 		assert.Equal(t, | ||||
| 			map[string]interface{}{ | ||||
| 				"multiple": []string{"1", "2"}, | ||||
| 				"single":   []string{"3"}, | ||||
| 			}, | ||||
| 			dest, | ||||
| 		) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ok, bind to map[string]int skips", func(t *testing.T) { | ||||
| 		dest := map[string]int{} | ||||
| 		assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param")) | ||||
| 		assert.Equal(t, map[string]int{}, dest) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("ok, bind to map[string][]int skips", func(t *testing.T) { | ||||
| 		dest := map[string][]int{} | ||||
| 		assert.NoError(t, new(DefaultBinder).bindData(&dest, exampleData, "param")) | ||||
| 		assert.Equal(t, map[string][]int{}, dest) | ||||
| 	}) | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestBindbindData(t *testing.T) { | ||||
| 	ts := new(bindTestStruct) | ||||
| 	b := new(DefaultBinder) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user