protected function doParse($className, $visited = array(), array $groups = array())
    {
        $meta = $this->factory->getMetadataForClass($className);

        if (null === $meta) {
            throw new \InvalidArgumentException(sprintf('No metadata found for class %s', $className));
        }

        $exclusionStrategies = array();
        if ($groups) {
            $exclusionStrategies[] = new GroupsExclusionStrategy($groups);
        }

        $params = array();

        // iterate over property metadata
        foreach ($meta->propertyMetadata as $item) {
            if (!is_null($item->type)) {
                $name = $this->namingStrategy->translateName($item);

                $dataType = $this->processDataType($item);

                // apply exclusion strategies
                foreach ($exclusionStrategies as $strategy) {
                    if (true === $strategy->shouldSkipProperty($item, SerializationContext::create())) {
                        continue 2;
                    }
                }

                $params[$name] = array(
                    'dataType' => $dataType['normalized'],
                    'required' => false,
                    'readonly' => $item->readOnly,
                    'sinceVersion' => $item->sinceVersion,
                    'untilVersion' => $item->untilVersion,
                );

                if (!is_null($dataType['class'])) {
                    $params[$name]['class'] = $dataType['class'];
                }

                // if class already parsed, continue, to avoid infinite recursion
                if (in_array($dataType['class'], $visited)) {
                    continue;
                }

                // check for nested classes with JMS metadata
                if ($dataType['class'] && null !== $this->factory->getMetadataForClass($dataType['class'])) {
                    $visited[] = $dataType['class'];
                    $params[$name]['children'] = $this->doParse($dataType['class'], $visited, $groups);
                }
            }
        }

        return $params;
    }