Browse Source

refactored metadata management

Johannes Schmitt 14 years ago
parent
commit
e863de797c

+ 35 - 0
Metadata/ClassHierarchyMetadata.php

@@ -0,0 +1,35 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata;
+
+class ClassHierarchyMetadata
+{
+    private $classes = array();
+
+    public function addClass(ClassMetadata $class)
+    {
+        $this->classes[$class->getName()] = $class;
+    }
+
+    public function getClasses()
+    {
+        return $this->classes;
+    }
+
+    public function getLastModified()
+    {
+        $time = 0;
+
+        foreach ($this->classes as $class) {
+            if (false !== $filename = $class->getReflection()->getFilename()) {
+                continue;
+            }
+
+            if ($time < $mtime = filemtime($filename)) {
+                $time = $mtime;
+            }
+        }
+
+        return $time;
+    }
+}

+ 67 - 0
Metadata/ClassMetadata.php

@@ -0,0 +1,67 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata;
+
+class ClassMetadata implements \Serializable
+{
+    private $name;
+    private $reflection;
+    private $properties = array();
+    private $exclusionPolicy = 'NONE';
+
+    public function __construct($name)
+    {
+        $this->name = $name;
+        $this->reflection = new \ReflectionClass($name);
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function getReflection()
+    {
+        return $this->reflection;
+    }
+
+    public function getProperties()
+    {
+        return $this->properties;
+    }
+
+    public function addPropertyMetadata(PropertyMetadata $metadata)
+    {
+        $this->properties[$metadata->getName()] = $metadata;
+    }
+
+    public function getExclusionPolicy()
+    {
+        return $this->exclusionPolicy;
+    }
+
+    public function setExclusionPolicy($policy)
+    {
+        $this->exclusionPolicy = $policy;
+    }
+
+    public function serialize()
+    {
+        return serialize(array(
+            $this->name,
+            $this->properties,
+            $this->exclusionPolicy,
+        ));
+    }
+
+    public function unserialize($str)
+    {
+        list(
+            $this->name,
+            $this->properties,
+            $this->exclusionPolicy
+        ) = unserialize($str);
+
+        $this->reflection = new \ReflectionClass($this->name);
+    }
+}

+ 60 - 0
Metadata/Driver/AnnotationDriver.php

@@ -0,0 +1,60 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata\Driver;
+
+use Annotations\ReaderInterface;
+use JMS\SerializerBundle\Annotation\Type;
+use JMS\SerializerBundle\Annotation\Exclude;
+use JMS\SerializerBundle\Annotation\Expose;
+use JMS\SerializerBundle\Annotation\SerializedName;
+use JMS\SerializerBundle\Annotation\Until;
+use JMS\SerializerBundle\Annotation\Since;
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
+use JMS\SerializerBundle\Annotation\ExclusionPolicy;
+use JMS\SerializerBundle\Mapping\ClassMetadata;
+
+class AnnotationDriver implements DriverInterface
+{
+    private $reader;
+
+    public function __construct(ReaderInterface $reader)
+    {
+        $this->reader = $reader;
+    }
+
+    public function loadMetadataForClass(\ReflectionClass $class)
+    {
+        $classMetadata = new ClassMetadata($name = $class->getName());
+        foreach ($this->reader->getClassAnnotations($class) as $annot) {
+            if ($annot instanceof ExclusionPolicy) {
+                $classMetadata->setExclusionPolicy($annot->getStrategy());
+            }
+        }
+
+        foreach ($class->getProperties() as $property) {
+            if ($property->getDeclaringClass()->getName() !== $name) {
+                continue;
+            }
+
+            $propertyMetadata = new PropertyMetadata($name, $property->getName());
+            foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
+                if ($annot instanceof Since) {
+                    $propertyMetadata->setSinceVersion($annot->getVersion());
+                } else if ($annot instanceof Until) {
+                    $propertyMetadata->setUntilVersion($annot->getVersion());
+                } else if ($annot instanceof SerializedName) {
+                    $propertyMetadata->setSerializedName($annot->getName());
+                } else if ($annot instanceof Expose) {
+                    $propertyMetadata->setExposed(true);
+                } else if ($annot instanceof Exclude) {
+                    $propertyMetadata->setExcluded(true);
+                } else if ($annot instanceof Type) {
+                    $propertyMetadata->setType($annot->getName());
+                }
+            }
+            $classMetadata->addPropertyMetadata($propertyMetadata);
+        }
+
+        return $classMetadata;
+    }
+}

+ 8 - 0
Metadata/Driver/DriverInterface.php

@@ -0,0 +1,8 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata\Driver;
+
+interface DriverInterface
+{
+    function loadMetadataForClass(\ReflectionClass $class);
+}

+ 46 - 0
Metadata/MetadataFactory.php

@@ -0,0 +1,46 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata;
+
+use JMS\SerializerBundle\Metadata\Driver\DriverInterface;
+
+class MetadataFactory
+{
+    private $driver;
+    private $loadedMetadata = array();
+    private $loadedClassMetadata = array();
+
+    public function __construct(DriverInterface $driver)
+    {
+        $this->driver = $driver;
+    }
+
+    public function getMetadataForClass($className)
+    {
+        if (isset($this->loadedMetadata[$className])) {
+            return $this->loadedMetadata[$className];
+        }
+
+        $metadata = new ClassHierarchyMetadata();
+        foreach ($this->getClassHierarchy($className) as $class) {
+            if (!isset($this->loadedClassMetadata[$name = $class->getName()])) {
+                $this->loadedClassMetadata[$name] = $this->driver->loadMetadataForClass($class);
+            }
+
+            $metadata->addClass($this->loadedClassMetadata[$name]);
+        }
+
+        return $this->loadedMetadata[$className] = $metadata;
+    }
+
+    private function getClassHierarchy($class)
+    {
+        $refl = new \ReflectionClass($class);
+        $classes = array();
+        do {
+            $classes[] = $refl;
+        } while (false !== $refl = $refl->getParentClass());
+
+        return array_reverse($classes, false);
+    }
+}

+ 133 - 0
Metadata/PropertyMetadata.php

@@ -0,0 +1,133 @@
+<?php
+
+namespace JMS\SerializerBundle\Metadata;
+
+class PropertyMetadata implements \Serializable
+{
+    private $class;
+    private $name;
+    private $reflection;
+    private $sinceVersion;
+    private $untilVersion;
+    private $serializedName;
+    private $exposed;
+    private $excluded;
+    private $type;
+
+    public function __construct($class, $name)
+    {
+        $this->class    = $class;
+        $this->name     = $name;
+        $this->exposed  = false;
+        $this->excluded = false;
+
+        $this->reflection = new \ReflectionProperty($class, $name);
+        $this->reflection->setAccessible(true);
+    }
+
+    public function getClass()
+    {
+        return $this->class;
+    }
+
+    public function getName()
+    {
+        return $this->name;
+    }
+
+    public function getReflection()
+    {
+        return $this->reflection;
+    }
+
+    public function setSinceVersion($version)
+    {
+        $this->sinceVersion = $version;
+    }
+
+    public function getSinceVersion()
+    {
+        return $this->sinceVersion;
+    }
+
+    public function setUntilVersion($version)
+    {
+        $this->untilVersion = $version;
+    }
+
+    public function getUntilVersion()
+    {
+        return $this->untilVersion;
+    }
+
+    public function setSerializedName($name)
+    {
+        $this->serializedName = $name;
+    }
+
+    public function getSerializedName()
+    {
+        return $this->serializedName;
+    }
+
+    public function setExposed($bool)
+    {
+        $this->exposed = (Boolean) $bool;
+    }
+
+    public function isExposed()
+    {
+        return $this->exposed;
+    }
+
+    public function setExcluded($bool)
+    {
+        $this->excluded = (Boolean) $bool;
+    }
+
+    public function isExcluded()
+    {
+        return $this->excluded;
+    }
+
+    public function setType($type)
+    {
+        $this->type = $type;
+    }
+
+    public function getType()
+    {
+        return $this->type;
+    }
+
+    public function serialize()
+    {
+        return serialize(array(
+            $this->class,
+            $this->name,
+            $this->sinceVersion,
+            $this->untilVersion,
+            $this->serializedName,
+            $this->exposed,
+            $this->excluded,
+            $this->type,
+        ));
+    }
+
+    public function unserialize($str)
+    {
+        list(
+            $this->class,
+            $this->name,
+            $this->sinceVersion,
+            $this->untilVersion,
+            $this->serializedName,
+            $this->exposed,
+            $this->excluded,
+            $this->type
+        ) = unserialize($str);
+
+        $this->reflection = new \ReflectionProperty($this->class, $this->name);
+        $this->reflection->setAccessible(true);
+    }
+}

+ 17 - 4
Resources/config/services.xml

@@ -5,6 +5,10 @@
     xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
 
     <parameters>
+        <parameter key="jms_serializer.metadata.driver.annotation_driver.class">JMS\SerializerBundle\Mapping\Driver\AnnotationDriver</parameter>
+        
+        <parameter key="jms_serializer.metadata.metadata_factory.class">JMS\SerializerBundle\Metadata\MetadataFactory</parameter>
+    
         <parameter key="jms_serializer.camel_case_naming_strategy.class">JMS\SerializerBundle\Serializer\Naming\CamelCaseNamingStrategy</parameter>
         <parameter key="jms_serializer.serialized_name_annotation_strategy.class">JMS\SerializerBundle\Serializer\Naming\SerializedNameAnnotationStrategy</parameter>
 
@@ -27,6 +31,17 @@
     </parameters>
 
     <services>
+        <!-- Metadata Drivers -->
+        <service id="jms_serializer.metadata.driver.annotation_driver" class="%jms_serializer.metadata.driver.annotation_driver.class%" public="false">
+            <argument type="service" id="annotation_driver" />
+        </service>
+        <service id="jms_serializer.metadata_driver" alias="jms_serializer.metadata.driver.annotation_driver" public="false" />
+
+        <!-- Metadata Factory -->
+        <service id="jms_serializer.metadata.metadata_factory" class="%jms_serializer.metadata.metadata_factory.class%" public="false">
+            <argument type="service" id="jms_serializer.metadata_driver" />
+        </service>
+
         <!-- Exclusion Strategies -->
         <service id="jms_serializer.version_exclusion_strategy"
                  class="%jms_serializer.version_exclusion_strategy.class%"
@@ -39,12 +54,10 @@
         <service id="jms_serializer.all_exclusion_strategy" 
                  class="%jms_serializer.all_exclusion_strategy.class%"
                  public="false">
-            <argument type="service" id="annotation_reader" />
         </service>
         <service id="jms_serializer.none_exclusion_strategy"
                  class="%jms_serializer.none_exclusion_strategy.class%"
                  public="false">
-            <argument type="service" id="annotation_reader" />
         </service>
 
         <!-- Exclusion Strategy Factories -->
@@ -63,7 +76,6 @@
         <!-- Naming Strategies -->
         <service id="jms_serializer.camel_case_naming_strategy" class="%jms_serializer.camel_case_naming_strategy.class%" public="false" />
         <service id="jms_serializer.serialized_name_annotation_strategy" class="%jms_serializer.serialized_name_annotation_strategy.class%" public="false">
-            <argument type="service" id="annotation_reader" />
             <argument type="service" id="jms_serializer.camel_case_naming_strategy" />
         </service>
         <service id="jms_serializer.naming_strategy" alias="jms_serializer.serialized_name_annotation_strategy" public="false" />
@@ -76,7 +88,7 @@
         <service id="jms_serializer.property_based_normalizer"
                  class="%jms_serializer.property_based_normalizer.class%"
                  public="false">
-            <argument type="service" id="annotation_reader" />
+            <argument type="service" id="jms_serializer.metadata.metadata_factory" />
             <argument type="service" id="jms_serializer.naming_strategy" />
         </service>
         <service id="jms_serializer.array_collection_normalizer"
@@ -100,6 +112,7 @@
         <service id="jms_serializer.serializer" 
                  class="%jms_serializer.serializer.class%" 
                  abstract="true">
+            <property name="container" type="service" id="service_container" />
             <argument type="service" id="jms_serializer.native_php_type_normalizer" strict="false" />
         </service>
         <service id="serializer" parent="jms_serializer.serializer">

+ 7 - 0
Resources/doc/index.rst

@@ -194,6 +194,8 @@ Available Types:
 |                           | Examples: array<string, string>,                 |
 |                           | array<string, MyNamespace\MyObject>, etc.        |
 +---------------------------+--------------------------------------------------+
+| DateTime                  | PHP's DateTime object                            |
++---------------------------+--------------------------------------------------+
 | T                         | Where T is a fully qualified class name.         |
 +---------------------------+--------------------------------------------------+
 | ArrayCollection<T>        | Similar to array<T>, but will be deserialized    |
@@ -228,6 +230,11 @@ Examples::
          */
         private $author;
 
+        /**
+         * @Type("DateTime")
+         */
+        private $createdAt;
+
         /**
          * @Type("boolean")
          */

+ 3 - 11
Serializer/Exclusion/AllExclusionStrategy.php

@@ -18,20 +18,12 @@
 
 namespace JMS\SerializerBundle\Serializer\Exclusion;
 
-use Annotations\ReaderInterface;
-use JMS\SerializerBundle\Annotation\Expose;
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
 
 class AllExclusionStrategy implements ExclusionStrategyInterface
 {
-    private $reader;
-
-    public function __construct(ReaderInterface $reader)
-    {
-        $this->reader = $reader;
-    }
-
-    public function shouldSkipProperty(\ReflectionProperty $property)
+    public function shouldSkipProperty(PropertyMetadata $property)
     {
-        return null === $this->reader->getPropertyAnnotation($property, 'JMS\SerializerBundle\Annotation\Expose');
+        return !$property->isExposed();
     }
 }

+ 3 - 1
Serializer/Exclusion/DisjunctExclusionStrategy.php

@@ -18,6 +18,8 @@
 
 namespace JMS\SerializerBundle\Serializer\Exclusion;
 
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
+
 class DisjunctExclusionStrategy implements ExclusionStrategyInterface
 {
     private $strategies;
@@ -27,7 +29,7 @@ class DisjunctExclusionStrategy implements ExclusionStrategyInterface
         $this->strategies = $strategies;
     }
 
-    public function shouldSkipProperty(\ReflectionProperty $property)
+    public function shouldSkipProperty(PropertyMetadata $property)
     {
         foreach ($this->strategies as $strategy) {
             if ($strategy->shouldSkipProperty($property)) {

+ 3 - 1
Serializer/Exclusion/ExclusionStrategyInterface.php

@@ -18,6 +18,8 @@
 
 namespace JMS\SerializerBundle\Serializer\Exclusion;
 
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
+
 /**
  * Interface for exclusion strategies.
  *
@@ -28,5 +30,5 @@ namespace JMS\SerializerBundle\Serializer\Exclusion;
  */
 interface ExclusionStrategyInterface
 {
-    function shouldSkipProperty(\ReflectionProperty $property);
+    function shouldSkipProperty(PropertyMetadata $property);
 }

+ 3 - 11
Serializer/Exclusion/NoneExclusionStrategy.php

@@ -18,20 +18,12 @@
 
 namespace JMS\SerializerBundle\Serializer\Exclusion;
 
-use Annotations\ReaderInterface;
-use JMS\SerializerBundle\Annotation\Exclude;
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
 
 class NoneExclusionStrategy implements ExclusionStrategyInterface
 {
-    private $reader;
-
-    public function __construct(ReaderInterface $reader)
-    {
-        $this->reader = $reader;
-    }
-
-    public function shouldSkipProperty(\ReflectionProperty $property)
+    public function shouldSkipProperty(PropertyMetadata $property)
     {
-        return null !== $this->reader->getPropertyAnnotation($property, 'JMS\SerializerBundle\Annotation\Exclude');
+        return $property->isExcluded();
     }
 }

+ 9 - 14
Serializer/Exclusion/VersionExclusionStrategy.php

@@ -18,30 +18,25 @@
 
 namespace JMS\SerializerBundle\Serializer\Exclusion;
 
-use Annotations\ReaderInterface;
-use JMS\SerializerBundle\Annotation\Until;
-use JMS\SerializerBundle\Annotation\Since;
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
 
 class VersionExclusionStrategy
 {
-    private $reader;
     private $version;
 
-    public function __construct(ReaderInterface $reader, $version)
+    public function __construct($version)
     {
-        $this->reader = $reader;
         $this->version = $version;
     }
 
-    public function shouldSkipProperty(\ReflectionProperty $property)
+    public function shouldSkipProperty(PropertyMetadata $property)
     {
-        $annotations = $this->reader->getPropertyAnnotations($property);
-        foreach ($annotations as $annotation) {
-            if ($annotation instanceof Since && version_compare($this->version, $annotation->getVersion(), '<')) {
-                return true;
-            } else if ($annotation instanceof Until && version_compare($this->version, $annotation->getVersion(), '>')) {
-                return true;
-            }
+        if ((null !== $version = $property->getSinceVersion()) && version_compare($this->version, $version, '<')) {
+            return true;
+        }
+
+        if ((null !== $version = $property->getUntilVersion()) && version_compare($this->version, $version, '>')) {
+            return true;
         }
 
         return false;

+ 1 - 1
Serializer/LazyLoadingSerializer.php

@@ -13,7 +13,7 @@ class LazyLoadingSerializer extends Serializer
         $encoder = parent::getEncoder($format);
 
         if (is_string($encoder)) {
-            $encoder = $container->get($encoder);
+            $encoder = $this->container->get($encoder);
 
             if ($encoder instanceof SerializerAwareInterface) {
                 $encoder->setSerializer($this);

+ 3 - 1
Serializer/Naming/CamelCaseNamingStrategy.php

@@ -18,6 +18,8 @@
 
 namespace JMS\SerializerBundle\Serializer\Naming;
 
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
+
 class CamelCaseNamingStrategy implements PropertyNamingStrategyInterface
 {
     private $separator;
@@ -29,7 +31,7 @@ class CamelCaseNamingStrategy implements PropertyNamingStrategyInterface
         $this->lowerCase = $lowerCase;
     }
 
-    public function translateName(\ReflectionProperty $property)
+    public function translateName(PropertyMetadata $property)
     {
         $separator = &$this->separator;
 

+ 3 - 1
Serializer/Naming/PropertyNamingStrategyInterface.php

@@ -18,6 +18,8 @@
 
 namespace JMS\SerializerBundle\Serializer\Naming;
 
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
+
 /**
  * Interface for property naming strategies.
  *
@@ -28,5 +30,5 @@ namespace JMS\SerializerBundle\Serializer\Naming;
  */
 interface PropertyNamingStrategyInterface
 {
-    function translateName(\ReflectionProperty $property);
+    function translateName(PropertyMetadata $property);
 }

+ 5 - 7
Serializer/Naming/SerializedNameAnnotationStrategy.php

@@ -18,24 +18,22 @@
 
 namespace JMS\SerializerBundle\Serializer\Naming;
 
-use Annotations\ReaderInterface;
 use JMS\SerializerBundle\Annotation\SerializedName;
+use JMS\SerializerBundle\Mapping\PropertyMetadata;
 
 class SerializedNameAnnotationStrategy implements PropertyNamingStrategyInterface
 {
-    private $reader;
     private $delegate;
 
-    public function __construct(ReaderInterface $reader, PropertyNamingStrategyInterface $namingStrategy)
+    public function __construct(PropertyNamingStrategyInterface $namingStrategy)
     {
-        $this->reader = $reader;
         $this->delegate = $namingStrategy;
     }
 
-    public function translateName(\ReflectionProperty $property)
+    public function translateName(PropertyMetadata $property)
     {
-        if (null !== $annot = $this->reader->getPropertyAnnotation($property, 'JMS\SerializerBundle\Annotation\SerializedName')) {
-            return $annot->getName();
+        if (null !== $name = $property->getSerializedName()) {
+            return $name;
         }
 
         return $this->delegate->translateName($property);

+ 25 - 109
Serializer/Normalizer/PropertyBasedNormalizer.php

@@ -18,11 +18,11 @@
 
 namespace JMS\SerializerBundle\Serializer\Normalizer;
 
-use Annotations\ReaderInterface;
 use JMS\SerializerBundle\Annotation\Type;
 use JMS\SerializerBundle\Annotation\ExclusionPolicy;
 use JMS\SerializerBundle\Exception\InvalidArgumentException;
 use JMS\SerializerBundle\Exception\UnsupportedException;
+use JMS\SerializerBundle\Metadata\MetadataFactory;
 use JMS\SerializerBundle\Serializer\Exclusion\ExclusionStrategyFactoryInterface;
 use JMS\SerializerBundle\Serializer\Exclusion\ExclusionStrategyInterface;
 use JMS\SerializerBundle\Serializer\Naming\PropertyNamingStrategyInterface;
@@ -32,18 +32,13 @@ use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer;
 
 class PropertyBasedNormalizer extends SerializerAwareNormalizer
 {
-    private $reader;
+    private $metadataFactory;
     private $propertyNamingStrategy;
     private $exclusionStrategyFactory;
-    private $exclusionStrategies = array();
-    private $reflectionData = array();
-    private $translatedNames = array();
-    private $excludedProperties = array();
-    private $propertyTypes = array();
 
-    public function __construct(ReaderInterface $reader, PropertyNamingStrategyInterface $propertyNamingStrategy, ExclusionStrategyFactoryInterface $exclusionStrategyFactory)
+    public function __construct(MetadataFactory $metadataFactory, PropertyNamingStrategyInterface $propertyNamingStrategy, ExclusionStrategyFactoryInterface $exclusionStrategyFactory)
     {
-        $this->reader = $reader;
+        $this->metadataFactory = $metadataFactory;
         $this->propertyNamingStrategy = $propertyNamingStrategy;
         $this->exclusionStrategyFactory = $exclusionStrategyFactory;
     }
@@ -54,32 +49,24 @@ class PropertyBasedNormalizer extends SerializerAwareNormalizer
             throw new UnsupportedException(sprintf('Type "%s" is not supported.', gettype($object)));
         }
 
-        // collect class hierarchy
-        list($class, $classes) = $this->getReflectionData(get_class($object));
+        $normalized = array();
+        $metadata = $this->metadataFactory->getMetadataForClass(get_class($object));
 
-        // go through properties and collect values
-        $normalized = $processed = array();
-        foreach ($classes as $class) {
-            $exclusionStrategy = $this->getExclusionStrategy($class);
-
-            foreach ($class->getProperties() as $property) {
-                if (isset($processed[$name = $property->getName()])) {
+        foreach ($metadata->getClasses() as $classMetadata) {
+            $exclusionStrategy = $this->exclusionStrategyFactory->getStrategy($classMetadata->getExclusionPolicy());
+            foreach ($classMetadata->getProperties() as $propertyMetadata) {
+                if ($exclusionStrategy->shouldSkipProperty($propertyMetadata)) {
                     continue;
                 }
-                $processed[$name] = true;
 
-                if ($this->shouldSkipProperty($exclusionStrategy, $property)) {
-                    continue;
-                }
-
-                $property->setAccessible(true);
-                $value = $this->serializer->normalize($property->getValue($object), $format);
+                $value = $this->serializer->normalize($propertyMetadata->getReflection()->getValue($object), $format);
 
+                // skip null-value properties
                 if (null === $value) {
                     continue;
                 }
 
-                $normalized[$this->translateName($property)] = $value;
+                $normalized[$this->propertyNamingStrategy->translateName($propertyMetadata)] = $value;
             }
         }
 
@@ -102,102 +89,31 @@ class PropertyBasedNormalizer extends SerializerAwareNormalizer
             throw new UnsupportedException(sprintf('Unsupported type; "%s" is not a valid class.', $type));
         }
 
-        list($class, $classes) = $this->getReflectionData($type);
-
+        $metadata = $this->metadataFactory->getMetadataForClass($type);
         $object = unserialize(sprintf('O:%d:"%s":0:{}', strlen($type), $type));
-        $processed = array();
-        foreach ($classes as $class) {
-            $exclusionStrategy = $this->getExclusionStrategy($class);
 
-            foreach ($class->getProperties() as $property) {
-                if (isset($processed[$name = $property->getName()])) {
+        foreach ($metadata->getClasses() as $classMetadata) {
+            $exclusionStrategy = $this->exclusionStrategyFactory->getStrategy($classMetadata->getExclusionPolicy());
+
+            foreach ($classMetadata->getProperties() as $propertyMetadata) {
+                if ($exclusionStrategy->shouldSkipProperty($propertyMetadata)) {
                     continue;
                 }
-                $processed[$name] = true;
 
-                if ($this->shouldSkipProperty($exclusionStrategy, $property)) {
+                $serializedName = $this->propertyNamingStrategy->translateName($propertyMetadata);
+                if(!array_key_exists($serializedName, $data)) {
                     continue;
                 }
 
-                $serializedName = $this->translateName($property);
-                if (!array_key_exists($serializedName, $data)) {
-                    continue;
+                if (null === $type = $propertyMetadata->getType()) {
+                    throw new \RuntimeException(sprintf('You must define the type for %s::$%s.', $propertyMetadata->getClass(), $propertyMetadata->getName()));
                 }
 
-                $value = $this->serializer->denormalize($data[$serializedName], $this->getType($property), $format);
-                $property->setAccessible(true);
-                $property->setValue($object, $value);
+                $value = $this->serializer->denormalize($data[$serializedName], $type, $format);
+                $propertyMetadata->getReflection()->setValue($object, $value);
             }
         }
 
         return $object;
     }
-
-    private function getType(\ReflectionProperty $property)
-    {
-        foreach ($this->reader->getPropertyAnnotations($property) as $annot) {
-            if ($annot instanceof Type) {
-                return $annot->getName();
-            }
-        }
-
-        throw new RuntimeException(sprintf('You need to add a "@Type" annotation for property "%s" in class "%s".', $property->getName(), $property->getDeclaringClass()->getName()));
-    }
-
-    private function translateName(\ReflectionProperty $property)
-    {
-        $key = $property->getDeclaringClass()->getName().'$'.$property->getName();
-        if (isset($this->translatedNames[$key])) {
-            return $this->translatedNames[$key];
-        }
-
-        return $this->translatedNames[$key] = $this->propertyNamingStrategy->translateName($property);
-    }
-
-    private function shouldSkipProperty(ExclusionStrategyInterface $exclusionStrategy, \ReflectionProperty $property)
-    {
-        $key = $property->getDeclaringClass()->getName().'$'.$property->getName();
-        if (isset($this->excludedProperties[$key])) {
-            return $this->excludedProperties[$key];
-        }
-
-        return $this->excludedProperties[$key] = $exclusionStrategy->shouldSkipProperty($property);
-    }
-
-    private function getExclusionStrategy(\ReflectionClass $class)
-    {
-        if (isset($this->exclusionStrategies[$name = $class->getName()])) {
-            return $this->exclusionStrategies[$name];
-        }
-
-        $annotations = $this->reader->getClassAnnotations($class);
-        foreach ($annotations as $annotation) {
-            if ($annotation instanceof ExclusionPolicy) {
-                return $this->exclusionStrategies[$name] =
-                    $this->exclusionStrategyFactory->getStrategy($annotation->getStrategy());
-            }
-        }
-
-        return $this->exclusionStrategies[$name] = $this->exclusionStrategyFactory->getStrategy('NONE');
-    }
-
-    private function getReflectionData($fqcn)
-    {
-        if (isset($this->reflectionData[$fqcn])) {
-            return $this->reflectionData[$fqcn];
-        }
-
-        $class = new \ReflectionClass($fqcn);
-        $classes = array();
-        do {
-            if (!$class->isUserDefined()) {
-                break;
-            }
-
-            $classes[] = $class;
-        } while (false !== $class = $class->getParentClass());
-        $classes = array_reverse($classes, false);
-
-        return $this->reflectionData[$fqcn] = array($class, $classes);
-    }
 }

+ 1 - 1
Tests/DependencyInjection/JMSSerializerExtensionTest.php

@@ -17,10 +17,10 @@ class JMSSerializerExtensionTest extends \PHPUnit_Framework_TestCase
 {
     public function testLoad()
     {
-        return;
         $extension = new JMSSerializerExtension();
         $container = new ContainerBuilder();
         $container->set('annotation_reader', new Reader());
+        $container->set('service_container', $container);
         $extension->load(array(array(
             'versions' => array('0.0.1', '1.1.1'),
         )), $container);