Index: ports/classes/net/xp_framework/unittest/reflection/FieldsTest.class.php =================================================================== --- ports/classes/net/xp_framework/unittest/reflection/FieldsTest.class.php (revision 12376) +++ ports/classes/net/xp_framework/unittest/reflection/FieldsTest.class.php (working copy) @@ -178,16 +178,41 @@ } /** + * Tests reading and writing the "date" field + * + * @see xp://lang.reflect.Field#get + * @see xp://lang.reflect.Field#set + */ + #[@test] + public function dateFieldRoundTrip() { + $instance= $this->fixture->newInstance(); + $date= Date::now(); + $field= $this->fixture->getField('date'); + $field->set($instance, $date); + $this->assertEquals($date, $field->get($instance)); + } + + /** * Tests retrieving the "date" field's value on a wrong object * * @see xp://lang.reflect.Field#get */ #[@test, @expect('lang.IllegalArgumentException')] - public function dateFieldValueOnWrongObject() { + public function getDateFieldValueOnWrongObject() { $this->fixture->getField('date')->get(new Object()); } /** + * Tests writing the "date" field's value on a wrong object + * + * @see xp://lang.reflect.Field#set + */ + #[@test, @expect('lang.IllegalArgumentException')] + public function setDateFieldValueOnWrongObject() { + $this->fixture->getField('date')->set(new Object(), Date::now()); + } + + /** * Tests retrieving the "initializerCalled" field's value * * @see xp://lang.reflect.Field#get @@ -198,26 +223,62 @@ } /** + * Tests retrieving the "initializerCalled" field's value + * + * @see xp://lang.reflect.Field#get + * @see xp://lang.reflect.Field#set + */ + #[@test] + public function initializerCalledFieldRoundTrip() { + with ($f= $this->fixture->getField('initializerCalled')); { + $f->set(NULL, FALSE); + $this->assertEquals(FALSE, $f->get(NULL)); + $f->set(NULL, TRUE); + $this->assertEquals(TRUE, $f->get(NULL)); + } + } + + /** * Tests retrieving the private static "cache" field's value * * @see xp://lang.reflect.Field#get */ #[@test, @expect('lang.IllegalAccessException')] - public function cacheFieldValue() { + public function getCacheFieldValue() { $this->fixture->getField('cache')->get(NULL); } /** + * Tests setting the private static "cache" field's value + * + * @see xp://lang.reflect.Field#set + */ + #[@test, @expect('lang.IllegalAccessException')] + public function setCacheFieldValue() { + $this->fixture->getField('cache')->set(NULL, array()); + } + + /** * Tests retrieving the protected "size" field's value * * @see xp://lang.reflect.Field#get */ #[@test, @expect('lang.IllegalAccessException')] - public function sizeFieldValue() { + public function getSizeFieldValue() { $this->fixture->getField('size')->get($this->fixture->newInstance()); } /** + * Tests setting the protected "size" field's value + * + * @see xp://lang.reflect.Field#set + */ + #[@test, @expect('lang.IllegalAccessException')] + public function setSizeFieldValue() { + $this->fixture->getField('size')->set($this->fixture->newInstance(), 1); + } + + /** * Tests retrieving the private "factor" field's value * * @see xp://lang.reflect.Field#get Index: skeleton/lang/reflect/Field.class.php =================================================================== --- skeleton/lang/reflect/Field.class.php (revision 12387) +++ skeleton/lang/reflect/Field.class.php (working copy) @@ -96,6 +96,41 @@ } /** + * Changes the value of the field represented by this Field, on the + * specified object. + * + * @param lang.Object instance + * @param mixed value + * @throws lang.IllegalArgumentException in case the passed object is not an instance of the declaring class + * @throws lang.IllegalAccessException in case this field is not public + */ + public function set($instance, $value) { + + // Verify the field is public + if (!($this->_reflect->getModifiers() & MODIFIER_PUBLIC)) { + throw new IllegalAccessException('Cannot write '.$this->toString()); + } + + // Short-circuit further checks for static members + if ($this->_reflect->isStatic()) { + return $this->_reflect->setValue(NULL, $value); + } + + // Verify given instance is instance of the class declaring this + // property + if (!($instance instanceof $this->_class)) { + throw new IllegalArgumentException(sprintf( + 'Passed argument is not a %s class (%s)', + xp::nameOf($this->_class), + xp::typeOf($instance) + )); + } + + + $this->_reflect->setValue($instance, $value); + } + + /** * Retrieve this field's modifiers * * @see xp://lang.reflect.Modifiers Index: skeleton/remote/protocol/Serializer.class.php =================================================================== --- skeleton/remote/protocol/Serializer.class.php (revision 12376) +++ skeleton/remote/protocol/Serializer.class.php (working copy) @@ -313,7 +313,7 @@ $serialized->offset++; // Opening "{" for ($i= 0; $i < $size; $i++) { $member= $this->valueOf($serialized, $context); - $instance->{$member}= $this->valueOf($serialized, $context); + $class->getField($member)->set($instance, $this->valueOf($serialized, $context)); } $serialized->offset++; // Closing "}" return $instance;