Show
Ignore:
Timestamp:
02/29/08 15:57:54 (9 months ago)
Author:
mikey
Message:

implemented enhancement #128: improved performance of XMLSerializer
Serializing a list of instances of the same object is much faster now.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/main/php/net/stubbles/xml/serializer/annotations/stubXMLMatcherAnnotation.php

    r1311 r1389  
    4848     * 
    4949     * @param   stubReflectionProperty  $property 
    50      * @param   mixed                   $propertyValue 
    5150     * @return  string|false 
    5251     * @throws  stubXMLException 
    5352     */ 
    54     public function getTagnameForProperty(stubReflectionProperty $property, $propertyValue
     53    public function getTagnameForProperty(stubReflectionProperty $property
    5554    { 
    5655        $matches = array(); 
     
    7574     * 
    7675     * @param   stubReflectionMethod  $method 
    77      * @param   mixed                 $returnValue 
    7876     * @return  string|bool 
    7977     * @throws  stubXMLException 
    8078     */ 
    81     public function getTagnameForMethod(stubReflectionMethod $method, $returnValue
     79    public function getTagnameForMethod(stubReflectionMethod $method
    8280    { 
    8381        $matches = array(); 
  • trunk/src/main/php/net/stubbles/xml/serializer/annotations/stubXMLMethodsAnnotation.php

    r1276 r1389  
    2424     * 
    2525     * @param   stubReflectionMethod  $method 
    26      * @param   mixed                 $returnValue 
    2726     * @return  string|false 
    2827     */ 
    29     public function getTagnameForMethod(stubReflectionMethod $method, $returnValue); 
     28    public function getTagnameForMethod(stubReflectionMethod $method); 
    3029} 
    3130?> 
  • trunk/src/main/php/net/stubbles/xml/serializer/annotations/stubXMLPropertiesAnnotation.php

    r1229 r1389  
    2424     * 
    2525     * @param   stubReflectionProperty  $property 
    26      * @param   mixed                   $propertyValue 
    2726     * @return  string|false 
    2827     */ 
    29     public function getTagnameForProperty(stubReflectionProperty $property, $propertyValue); 
     28    public function getTagnameForProperty(stubReflectionProperty $property); 
    3029} 
    3130?> 
  • trunk/src/main/php/net/stubbles/xml/serializer/matcher/stubXMLSerializerMethodPropertyMatcher.php

    r1385 r1389  
    2626    public function matchesMethod(ReflectionMethod $method) 
    2727    { 
    28         if ($method->isPublic() === false) { 
     28        if ($method->isPublic() === false || $method->isStatic() === true) { 
    2929            return false; 
    3030        } 
     
    6464    public function matchesProperty(ReflectionProperty $property) 
    6565    { 
    66         return $property->isPublic(); 
     66        if ($property->isPublic() === false || $property->isStatic() === true) { 
     67            return false; 
     68        } 
     69         
     70        return true; 
    6771    } 
    6872 
  • trunk/src/main/php/net/stubbles/xml/serializer/stubXMLSerializer.php

    r1385 r1389  
    44 * 
    55 * @author      Stephan Schmidt <schst@stubbles.net> 
     6 * @author      Frank Kleine <mikey@stubbles.net> 
    67 * @package     stubbles 
    78 * @subpackage  xml_serializer 
    89 */ 
    9 stubClassLoader::load('net::stubbles::xml::serializer::annotations::stubXMLTagAnnotation', 
    10                       'net::stubbles::xml::serializer::annotations::stubXMLFragmentAnnotation', 
    11                       'net::stubbles::xml::serializer::annotations::stubXMLAttributeAnnotation', 
    12                       'net::stubbles::xml::serializer::annotations::stubXMLIgnoreAnnotation', 
    13                       'net::stubbles::xml::serializer::annotations::stubXMLPropertiesAnnotation', 
    14                       'net::stubbles::xml::serializer::annotations::stubXMLMethodsAnnotation', 
    15                       'net::stubbles::xml::serializer::annotations::stubXMLMatcherAnnotation', 
    16                       'net::stubbles::xml::serializer::annotations::stubXMLStrategyAnnotation', 
    17                       'net::stubbles::xml::serializer::matcher::stubXMLSerializerMethodPropertyMatcher', 
    18                       'net::stubbles::reflection::reflection' 
     10stubClassLoader::load('net::stubbles::xml::stubXMLStreamWriter', 
     11                      'net::stubbles::xml::serializer::stubXMLSerializerObjectData' 
    1912); 
    2013/** 
     
    3528    const OPT_STRATEGY     = 'strategy'; 
    3629    /** 
    37      * Option to define the strategy 
    38      */ 
    39     const OPT_STATIC       = 'static'; 
    40     /** 
    4130     * Do not export any properties or methods 
    4231     */ 
     
    6049     */ 
    6150    private $defaultOpts = array(self::OPT_ROOT_TAG => null, 
    62                                  self::OPT_STRATEGY => self::STRATEGY_ALL, 
    63                                  self::OPT_STATIC   => false 
     51                                 self::OPT_STRATEGY => self::STRATEGY_ALL 
    6452                           ); 
    6553    /** 
     
    6957     */ 
    7058    private $opts; 
    71     /** 
    72      * the matcher to be used for methods and properties 
    73      * 
    74      * @var  stubXMLSerializerMethodPropertyMatcher 
    75      */ 
    76     protected $methodAndPropertyMatcher; 
    77  
    78     /** 
    79      * constructor 
    80      */ 
    81     public function __construct() 
    82     { 
    83         $this->methodAndPropertyMatcher = new stubXMLSerializerMethodPropertyMatcher(); 
    84     } 
    85  
    86     /** 
    87      * Serialize any data structure to XML 
    88      * 
    89      * @param  mixed                $data       The data to serialize 
    90      * @param  stubXMLStreamWriter  $xmlWriter  The XML Writer to use 
     59 
     60    /** 
     61     * serialize any data structure to XML 
     62     * 
     63     * @param  mixed                $data       data to serialize 
     64     * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use 
    9165     * @param  array                $opts       Options to influence the serializing 
    9266     */ 
    93     public function serialize($data, stubXMLStreamWriter $xmlWriter, $opts = array()) 
     67    public function serialize($data, stubXMLStreamWriter $xmlWriter, array $opts = array()) 
    9468    { 
    9569        // set the currently used options 
     
    9973 
    10074    /** 
    101      * Serialize any data structure to XML 
    102      * 
    103      * @param  mixed                $data       The data to serialize 
    104      * @param  stubXMLStreamWriter  $xmlWriter  The XML Writer to use 
    105      * @param  string               $tagName    The name of the XML tag 
     75     * serialize any data structure to XML 
     76     * 
     77     * @param  mixed                $data       data to serialize 
     78     * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use 
     79     * @param  string               $tagName    name of the XML tag 
    10680     */ 
    10781    protected function serializeDispatcher($data, stubXMLStreamWriter $xmlWriter, $tagName = null) 
     
    10983        switch (gettype($data)) { 
    11084            case 'NULL': 
    111                 if ($tagName === null) { 
     85                if (null === $tagName) { 
    11286                    $tagName = 'null'; 
    11387                } 
     
    12094             
    12195            case 'boolean': 
    122                 if ($tagName === null) { 
     96                if (null === $tagName) { 
    12397                    $tagName = 'boolean'; 
    12498                } 
     
    132106            case 'integer': 
    133107            case 'double': 
    134                 if ($tagName === null) { 
     108                if (null === $tagName) { 
    135109                    $tagName = gettype($data); 
    136110                } 
     
    150124             
    151125            default: 
    152                 // do not serialize other data types as they can not be serialized 
    153         } 
    154     } 
    155  
    156     /** 
    157      * Serialize an object 
    158      * 
    159      * @param  object               $object 
    160      * @param  stubXMLStreamWriter  $xmlWriter 
    161      * @param  string               $tagName 
    162      * @todo   Refactor this method into smaller methods for improved readability 
     126                // nothing to do 
     127        } 
     128    } 
     129 
     130    /** 
     131     * serialize an object 
     132     * 
     133     * @param  object               $object     object to serialize 
     134     * @param  stubXMLStreamWriter  $xmlWriter  XML Writer to use 
     135     * @param  string               $tagName    name of the XML tag 
    163136     */ 
    164137    protected function serializeObject($object, stubXMLStreamWriter $xmlWriter, $tagName) 
    165138    { 
    166         $clazz = new stubReflectionClass(get_class($object)); 
     139        $serializerData = stubXMLSerializerObjectData::fromObject($object); 
     140        $xmlWriter->writeStartElement($serializerData->getTagName($tagName)); 
     141        $strategy = $serializerData->getStrategy($this->opts[self::OPT_STRATEGY]); 
     142        foreach ($serializerData->getProperties() as $propertyName => $propertyData) { 
     143            $this->handle($object->$propertyName, $xmlWriter, $propertyData, ($strategy & self::STRATEGY_PROPS)); 
     144        } 
     145         
     146        foreach ($serializerData->getMethods() as $methodName => $methodData) { 
     147            $this->handle($object->$methodName(), $xmlWriter, $methodData, ($strategy & self::STRATEGY_METHODS)); 
     148        } 
     149         
     150        $xmlWriter->writeEndElement(); 
     151    } 
     152 
     153    /** 
     154     * serializes given value with instructions from $data 
     155     * 
     156     * @param  mixed                               $value          the value to serialize 
     157     * @param  stubXMLStreamWriter                 $xmlWriter      XML Writer to use 
     158     * @param  array<string,array<string,scalar>>  $data           instructions on how to serialize 
     159     * @param  int                                 $mustSerialize  whether the element must be serialized or not 
     160     */ 
     161    protected function handle($value, stubXMLStreamWriter $xmlWriter, array $data, $mustSerialize) 
     162    { 
     163        switch ($data['type']) { 
     164            case 'attribute': 
     165                if ('' === (string) $value && true === $data['shouldSkipEmpty']) { 
     166                    return; 
     167                } 
     168                 
     169                $xmlWriter->writeAttribute($data['attributeName'], (string) $value); 
     170                break; 
     171             
     172            case 'fragment': 
     173                if (null != $data['tagName']) { 
     174                    $xmlWriter->writeStartElement($data['tagName']); 
     175                    $xmlWriter->writeXmlFragment($value); 
     176                    $xmlWriter->writeEndElement(); 
     177                } else { 
     178                    $xmlWriter->writeXmlFragment($value); 
     179                } 
     180                break; 
     181             
     182            default: 
     183                if (false === $data['mustSerialize'] && 0 === $mustSerialize) { 
     184                    return; 
     185                } 
     186                 
     187                if (is_array($value) === true) { 
     188                    $this->serializeArray($value, $xmlWriter, $data['tagName'], $data['elementName']); 
     189                } else { 
     190                    $this->serializeDispatcher($value, $xmlWriter, $data['tagName']); 
     191                } 
     192        } 
     193    } 
     194 
     195    /** 
     196     * serialize an array 
     197     * 
     198     * @param  array                $array       array to serialize 
     199     * @param  stubXMLStreamWriter  $xmlWriter   XML Writer to use 
     200     * @param  string               $tagName     'root' name for the array 
     201     * @param  string               $defaultTag  The default tag for indexed arrays 
     202     */ 
     203    protected function serializeArray($array, stubXMLStreamWriter $xmlWriter, $tagName, $defaultTag = null) 
     204    { 
    167205        if (null === $tagName) { 
    168             if ($clazz->hasAnnotation('XMLTag') === true) { 
    169                 $tagName = $clazz->getAnnotation('XMLTag')->getTagName(); 
    170             } else { 
    171                 $tagName = get_class($object); 
    172             } 
    173         } 
    174  
    175         $xmlWriter->writeStartElement($tagName); 
    176         if ($clazz->hasAnnotation('XMLStrategy')) { 
    177             $strategy = $clazz->getAnnotation('XMLStrategy')->getValue(); 
    178         } else { 
    179             $strategy = $this->opts[self::OPT_STRATEGY]; 
    180         } 
    181  
    182         // export props 
    183         $properties = $clazz->getPropertiesByMatcher($this->methodAndPropertyMatcher); 
    184         $matcher    = null; 
    185         // get the property-matcher 
    186         if ($clazz->hasAnnotation('XMLProperties')) { 
    187             $matcher = $clazz->getAnnotation('XMLProperties'); 
    188         } 
    189  
    190         foreach ($properties as $property) { 
    191             $propValue = $property->getValue($object); 
    192             if ($this->writeAnnotatedElement($property, $xmlWriter, $propValue) === true) { 
    193                 continue; 
    194             } 
    195              
    196             if ($property->hasAnnotation('XMLTag') === true) { 
    197                 $xmlTag      = $property->getAnnotation('XMLTag'); 
    198                 $tagName     = $xmlTag->getTagName(); 
    199                 $elementName = $xmlTag->getElementTagName(); 
    200             } else { 
    201                 if (null !== $matcher) { 
    202                     $tagName = $matcher->getTagnameForProperty($property, $propValue); 
    203                     if (false === $tagName) { 
    204                         continue; 
    205                     } 
    206                 } else { 
    207                     if (($strategy & self::STRATEGY_PROPS) === 0) { 
    208                         continue; 
    209                     } 
    210                      
    211                     if ($this->opts[self::OPT_STATIC] === false && $property->isStatic() === true) { 
    212                         continue; 
    213                     } 
    214                      
    215                     $tagName = $property->getName(); 
    216                 } 
    217                 $elementName = null; 
    218             } 
    219              
    220             if (is_array($propValue) === true) { 
    221                 $this->serializeArray($propValue, $xmlWriter, $tagName, $elementName); 
    222             } else { 
    223                 $this->serializeDispatcher($propValue, $xmlWriter, $tagName); 
    224             } 
    225         } 
    226  
    227         // export methods 
    228         $methods = $clazz->getMethodsByMatcher($this->methodAndPropertyMatcher); 
    229         $matcher = null; 
    230         // get the method-matcher 
    231         if ($clazz->hasAnnotation('XMLMethods')) { 
    232             $matcher = $clazz->getAnnotation('XMLMethods'); 
    233         } 
    234          
    235         foreach ($methods as $method) { 
    236             $returnValue = $method->invoke($object); 
    237             if ($this->writeAnnotatedElement($method, $xmlWriter, $returnValue) === true) { 
    238                 continue; 
    239             } 
    240              
    241             if ($method->hasAnnotation('XMLTag') === true) { 
    242                 $xmlTag      = $method->getAnnotation('XMLTag'); 
    243                 $tagName     = $xmlTag->getTagName(); 
    244                 $elementName = $xmlTag->getElementTagName(); 
    245             } else { 
    246                 if (null !== $matcher) { 
    247                     $tagName = $matcher->getTagnameForMethod($method, $returnValue); 
    248                     if (false === $tagName) { 
    249                         continue; 
    250                     } 
    251                 } else { 
    252                     if (($strategy & self::STRATEGY_METHODS) === 0) { 
    253                         continue; 
    254                     } 
    255                      
    256                     if ($this->opts[self::OPT_STATIC] === false && $method->isStatic() === true) { 
    257                         continue; 
    258                     } 
    259  
    260                     $tagName = $method->getName(); 
    261                 } 
    262                  
    263                 $elementName = null; 
    264             } 
    265  
    266             if (is_array($returnValue) === true) { 
    267                 $this->serializeArray($returnValue, $xmlWriter, $tagName, $elementName); 
    268             } else { 
    269                 $this->serializeDispatcher($returnValue, $xmlWriter, $tagName); 
    270             } 
    271         } 
    272          
    273         $xmlWriter->writeEndElement(); 
    274     } 
    275  
    276     /** 
    277      * serializes annotated element 
    278      * 
    279      * Returns true if element was serialized, else false. 
    280      * 
    281      * @param   stubAnnotatable      $annotatable  the annotatable element to serialize 
    282      * @param   stubXMLStreamWriter  $xmlWriter    the xml writer to use 
    283      * @param   mixed                $value        the value to serialize 
    284      * @return  bool 
    285      */ 
    286     protected function writeAnnotatedElement(stubAnnotatable $annotatable, stubXMLStreamWriter $xmlWriter, $value) 
    287     { 
    288         if ($annotatable->hasAnnotation('XMLAttribute') === true) { 
    289             $xmlAttribute = $annotatable->getAnnotation('XMLAttribute'); 
    290             if ('' === (string) $value && $xmlAttribute->shouldSkipEmpty() === true) { 
    291                 return true; 
    292             } 
    293              
    294             $xmlWriter->writeAttribute($xmlAttribute->getAttributeName(), (string) $value); 
    295             return true; 
    296         } elseif ($annotatable->hasAnnotation('XMLFragment') === true) { 
    297             $tagName = $annotatable->getAnnotation('XMLFragment')->getTagName(); 
    298             if (null != $tagName) { 
    299                 $xmlWriter->writeStartElement($tagName); 
    300                 $xmlWriter->writeXmlFragment($value); 
    301                 $xmlWriter->writeEndElement(); 
    302             } else { 
    303                 $xmlWriter->writeXmlFragment($value); 
    304             } 
    305              
    306             return true; 
    307         } 
    308          
    309         return false; 
    310     } 
    311  
    312     /** 
    313      * Serialize an array 
    314      * 
    315      * @param  array                $array 
    316      * @param  stubXMLStreamWriter  $xmlWriter 
    317      * @param  string               $tagName     The 'root' name for the array 
    318      * @param  string               $defaultTag  The default tag for indexed arrays 
    319      */ 
    320     protected function serializeArray($array, stubXMLStreamWriter $xmlWriter, $tagName, $defaultTag = null) 
    321     { 
    322         if ($tagName === null) { 
    323206            $tagName = 'array'; 
    324207        } 
    325208         
    326         if ($tagName !== false) { 
     209        if (false !== $tagName) { 
    327210            $xmlWriter->writeStartElement($tagName); 
    328211        } 
    329212         
    330213        foreach ($array as $key => $value) { 
    331             if (is_int($key)) { 
     214            if (is_int($key) === true) { 
    332215                if (null === $defaultTag) { 
    333216                    $this->serializeDispatcher($value, $xmlWriter); 
     
    340223        } 
    341224         
    342         if ($tagName !== false) { 
     225        if (false !== $tagName) { 
    343226            $xmlWriter->writeEndElement(); 
    344227        }