func hydrateProperties(v reflect.Value, component *token) error { vdref := dereferencePointerValue(v) vtype := vdref.Type() vkind := vdref.Kind() if vkind != reflect.Struct { return utils.NewError(hydrateProperties, "unable to hydrate properties of non-struct", v, nil) } n := vtype.NumField() for i := 0; i < n; i++ { prop := properties.PropertyFromStructField(vtype.Field(i)) if prop == nil { continue // skip if field is ignored } vfield := vdref.Field(i) // first try to hydrate property values if properties, ok := component.properties[prop.Name]; ok { for _, prop := range properties { if err := hydrateProperty(vfield, prop); err != nil { msg := fmt.Sprintf("unable to hydrate property %s", prop.Name) return utils.NewError(hydrateProperties, msg, v, err) } } } // then try to hydrate components vtemp, _ := newValue(vfield) if tag, err := extractTagFromValue(vtemp); err != nil { msg := fmt.Sprintf("unable to extract tag from property %s", prop.Name) return utils.NewError(hydrateProperties, msg, v, err) } else if components, ok := component.components[tag]; ok { for _, comp := range components { if err := hydrateNestedComponent(vfield, comp); err != nil { msg := fmt.Sprintf("unable to hydrate component %s", prop.Name) return utils.NewError(hydrateProperties, msg, v, err) } } } } return nil }
func marshalStruct(v reflect.Value) (string, error) { var out []string // iterate over all fields vtype := v.Type() n := vtype.NumField() for i := 0; i < n; i++ { // keep a reference to the field value and definition fv := v.Field(i) fs := vtype.Field(i) // use the field definition to extract out property defaults p := properties.PropertyFromStructField(fs) if p == nil { continue // skip explicitly ignored fields and private members } fi := fv.Interface() // some fields are not properties, but actually nested objects. // detect those early using the property and object encoder... if _, ok := fi.(properties.CanEncodeValue); !ok && !isInvalidOrEmptyValue(fv) { if encoded, err := encode(fv, objectEncoder); err != nil { msg := fmt.Sprintf("unable to encode field %s", fs.Name) return "", utils.NewError(marshalStruct, msg, v.Interface(), err) } else if encoded != "" { // encoding worked! no need to process as a property out = append(out, encoded) continue } } // now check to see if the field value overrides the defaults... if !isInvalidOrEmptyValue(fv) { // first, check the field value interface for overrides... if overrides, err := properties.PropertyFromInterface(fi); err != nil { msg := fmt.Sprintf("field %s failed validation", fs.Name) return "", utils.NewError(marshalStruct, msg, v.Interface(), err) } else if p.Merge(overrides); p.Value == "" { // then, if we couldn't find an override from the interface, // try the simple string encoder... if p.Value, err = stringEncoder(fv); err != nil { msg := fmt.Sprintf("unable to encode field %s", fs.Name) return "", utils.NewError(marshalStruct, msg, v.Interface(), err) } } } // make sure we have a value by this point if !p.HasNameAndValue() { if p.OmitEmpty { continue } else if p.DefaultValue != "" { p.Value = p.DefaultValue } else if p.Required { msg := fmt.Sprintf("missing value for required field %s", fs.Name) return "", utils.NewError(Marshal, msg, v.Interface(), nil) } } // encode in the property out = append(out, properties.MarshalProperty(p)) } // wrap the fields in the enclosing struct tags return tagAndJoinValue(v, out) }