Reflection - method call panics with "call of reflect.Value.Elem on struct Value"
Asked Answered
T

1

8

Here is a code snippet -

type Gateway struct {
    Svc1 svc1.Interface
    Svc2 svc2.Interface
}

func (g *Gateway) GetClient(service string) interface{} {
    ps := reflect.ValueOf(g)
    s := ps.Elem()
    f := s.FieldByName(strings.Title(service))
    return f.Interface()
}

func (g *Gateway) Invoke(service string, endpoint string, args... 
    interface{}) []reflect.Value {
    log.Info("Gateway.Invoke " + service + "." + endpoint)
    inputs := make([]reflect.Value, len(args))
    for i, _ := range args {
        inputs[i] = reflect.ValueOf(args[i])
    }

    client := g.GetClient(service)

    return reflect.ValueOf(client).Elem().MethodByName(endpoint).Call(inputs)
}

GetClient("svc1") works fine.

However, when I call Invoke("svc1", "endpoint1", someArg), it panics saying -

reflect: call of reflect.Value.Elem on struct Value

reflect.ValueOf(client).MethodByName(endpoint).Call(inputs) panics saying Call on a zero value.

Twoseater answered 15/6, 2017 at 11:25 Comment(2)
I tried the solution for this - #14117340 and I am calling Invoke("svc1", "Endpoint1", someArgs). Now it does not crash, but can't find the Endpoint1 method as well. How ever if I do a type assertion on GetClient's result and call Endpoint1, that works fine.Twoseater
Does this answer your question? Dynamically call method on interface{} regardless of receiver typeDurtschi
M
12

There are a couple issues:

  1. If svc1.Interface is not a pointer or an interface, reflect.Value.Elem() will panic (see https://golang.org/pkg/reflect/#Value.Elem)

  2. If the endpoint argument string of Invoke doesn't match the capitalization of the target method, it will panic due to zero value (invalid reflect.Value). Please note that the method you want to call must be exported.

Mambo answered 15/6, 2017 at 14:6 Comment(2)
Yes realized that after looking at #14117340 Trying to find a way to mark my question as duplicate of that one without down-voting myself :DTwoseater
In my in case the interface was not a pointer. Changing it to pointer resolved it.Wolgast

© 2022 - 2024 — McMap. All rights reserved.