public function testValueObject()
 {
     $type = new Type(Type::BUILTIN_TYPE_STRING);
     $metadata = new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'desc', true, true, false, false, true, false, 'http://example.com/foo', null, ['foo' => 'bar']);
     $this->assertEquals($type, $metadata->getType());
     $this->assertEquals('desc', $metadata->getDescription());
     $this->assertTrue($metadata->isReadable());
     $this->assertTrue($metadata->isWritable());
     $this->assertFalse($metadata->isReadableLink());
     $this->assertFalse($metadata->isWritableLink());
     $this->assertTrue($metadata->isRequired());
     $this->assertFalse($metadata->isIdentifier());
     $this->assertEquals('http://example.com/foo', $metadata->getIri());
     $this->assertEquals(['foo' => 'bar'], $metadata->getAttributes());
     $newType = new Type(Type::BUILTIN_TYPE_BOOL);
     $newMetadata = $metadata->withType($newType);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertEquals($newType, $newMetadata->getType());
     $newMetadata = $metadata->withDescription('description');
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertEquals('description', $newMetadata->getDescription());
     $newMetadata = $metadata->withReadable(false);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertFalse($newMetadata->isReadable());
     $newMetadata = $metadata->withWritable(false);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertFalse($newMetadata->isWritable());
     $newMetadata = $metadata->withReadableLink(true);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertTrue($newMetadata->isReadableLink());
     $newMetadata = $metadata->withWritableLink(true);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertTrue($newMetadata->isWritableLink());
     $newMetadata = $metadata->withRequired(false);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertFalse($newMetadata->isRequired());
     $newMetadata = $metadata->withIdentifier(true);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertTrue($newMetadata->isIdentifier());
     $newMetadata = $metadata->withIri('foo:bar');
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertEquals('foo:bar', $newMetadata->getIri());
     $newMetadata = $metadata->withAttributes(['a' => 'b']);
     $this->assertNotSame($metadata, $newMetadata);
     $this->assertEquals(['a' => 'b'], $newMetadata->getAttributes());
 }
 /**
  * Denormalizes a relation.
  *
  * @param string           $attributeName
  * @param PropertyMetadata $propertyMetadata
  * @param string           $className
  * @param mixed            $value
  * @param string|null      $format
  * @param array            $context
  *
  * @throws InvalidArgumentException
  *
  * @return object|null
  */
 private function denormalizeRelation(string $attributeName, PropertyMetadata $propertyMetadata, string $className, $value, string $format = null, array $context)
 {
     if (is_string($value)) {
         try {
             return $this->iriConverter->getItemFromIri($value, $context + ['fetch_data' => false]);
         } catch (InvalidArgumentException $e) {
             // Give a chance to other normalizers (e.g.: DateTimeNormalizer)
         }
     }
     if (!$this->resourceClassResolver->isResourceClass($className) || $propertyMetadata->isWritableLink()) {
         return $this->serializer->denormalize($value, $className, $format, $this->createRelationSerializationContext($className, $context));
     }
     if (!is_array($value)) {
         throw new InvalidArgumentException(sprintf('Expected IRI or nested document for attribute "%s", "%s" given.', $attributeName, gettype($value)));
     }
     throw new InvalidArgumentException(sprintf('Nested documents for attribute "%s" are not allowed. Use IRIs instead.', $attributeName));
 }