private static function _validate($fields, $parents, $skip, $baseRef)
    {
        $valid = true;
        $blacklist = [];
        if (is_object($fields)) {
            if (in_array($fields, $skip, true)) {
                return true;
            }
            $skip[] = $fields;
            $blacklist = property_exists($fields, '_blacklist') ? $fields::$_blacklist : [];
        }

        foreach ($fields as $field => $value) {
            if ($value === null || is_scalar($value) || in_array($field, $blacklist)) {
                continue;
            }
            $ref = $baseRef !== '' ? $baseRef.'/'.urlencode((string)$field) : urlencode((string)$field);
            if (is_object($value)) {
                if (method_exists($value, 'validate')) {
                    if (!$value->validate($parents, $skip, $ref)) {
                        $valid = false;
                    }
                } elseif (!self::_validate($value, $parents, $skip, $ref)) {
                    $valid = false;
                }
            } elseif (is_array($value) && !self::_validate($value, $parents, $skip, $ref)) {
                $valid = false;
            }
        }
        return $valid;
    }