UnmarshalCmd unmarshals a JSON-RPC request into a suitable concrete command so long as the method type contained within the marshalled request is registered.


func UnmarshalCmd(r *Request) (interface{}, error) {
	rtp, ok := methodToConcreteType[r.Method]
	info := methodToInfo[r.Method]
	if !ok {
		str := fmt.Sprintf("%q is not registered", r.Method)
		return nil, makeError(ErrUnregisteredMethod, str)
	rt := rtp.Elem()
	rvp := reflect.New(rt)
	rv := rvp.Elem()

	// Ensure the number of parameters are correct.
	numParams := len(r.Params)
	if err := checkNumParams(numParams, &info); err != nil {
		return nil, err

	// Loop through each of the struct fields and unmarshal the associated
	// parameter into them.
	for i := 0; i < numParams; i++ {
		rvf := rv.Field(i)
		// Unmarshal the parameter into the struct field.
		concreteVal := rvf.Addr().Interface()
		if err := json.Unmarshal(r.Params[i], &concreteVal); err != nil {
			// The most common error is the wrong type, so
			// explicitly detect that error and make it nicer.
			fieldName := strings.ToLower(rt.Field(i).Name)
			if jerr, ok := err.(*json.UnmarshalTypeError); ok {
				str := fmt.Sprintf("parameter #%d '%s' must "+
					"be type %v (got %v)", i+1, fieldName,
					jerr.Type, jerr.Value)
				return nil, makeError(ErrInvalidType, str)

			// Fallback to showing the underlying error.
			str := fmt.Sprintf("parameter #%d '%s' failed to "+
				"unmarshal: %v", i+1, fieldName, err)
			return nil, makeError(ErrInvalidType, str)

	// When there are less supplied parameters than the total number of
	// params, any remaining struct fields must be optional.  Thus, populate
	// them with their associated default value as needed.
	if numParams < info.maxParams {
		populateDefaults(numParams, &info, rv)

	return rvp.Interface(), nil