Issue 1:
Description

The documentation for ObjectNormalizer states that "It supports calling the constructor during the denormalization process." but that is not true when one of the constructor arguments is an array of objects. Currently (since #19649), is is only possible to denormalize an "array of objects" property if that property has a setter method or is public.

Example

#!/usr/bin/env php
<?php

namespace App;

use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

require __DIR__ . '/vendor/autoload.php';

class Item
{
/**
* @var string
*/
private $id;

/**
* Item constructor.
* @param string $id
*/
public function __construct(string $id)
{
$this->id = $id;
}

public function getId(): string
{
return $this->id;
}
}

class Pack
{
/**
* @var Item[]
*/
private $items;

/**
* Pack constructor.
* @param Item[] $items
*/
public function __construct(array $items)
{
$this->items = $items;
}

public function getItems(): array
{
return $this->items;
}
}

$phpDocExtractor = new PhpDocExtractor();
$normalizer = new ObjectNormalizer(null, null, null, $phpDocExtractor);
$serializer = new Serializer([$normalizer, new ArrayDenormalizer()]);

$itemData = ["id" => "1"];
$listData = ['items' => [$itemData]];

dump($serializer->denormalize($listData, Pack::class));

Executing this script from a project root will print:

App\Pack {#20
-items: array:1 [
0 => array:1 [
"id" => "1"
]
]
}

The expected result is:

App\Pack {#18
-items: array:1 [
0 => App\Item {#40
-id: "1"
}
]
}

That expected result can be obtained by replacing the constructor of Pack with a setter for $items:

#!/usr/bin/env php
<?php

namespace App;

use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;

require __DIR__ . '/vendor/autoload.php';

class Item
{
/**
* @var string
*/
private $id;

/**
* Item constructor.
* @param string $id
*/
public function __construct(string $id)
{
$this->id = $id;
}

public function getId(): string
{
return $this->id;
}
}

class Pack
{
/**
* @var Item[]
*/
private $items;

public function setItems(array $items): self
{
$this->items = $items;

return $this;
}

public function getItems(): array
{
return $this->items;
}
}

$phpDocExtractor = new PhpDocExtractor();
$normalizer = new ObjectNormalizer(null, null, null, $phpDocExtractor);
$serializer = new Serializer([$normalizer, new ArrayDenormalizer()]);

$itemData = ["id" => "1"];
$listData = ['items' => [$itemData]];

dump($serializer->denormalize($listData, Pack::class));

Issue 2:
Currently when a property is private and no getter is defined, symfony won't get the value in an object's property, instead an exception will be thrown. However the private property could very well be accessible using the magic __call method. Actually this is very useful to have for Doctrine entities that extend the Doctrine\Common\Persistence\PersistentObject abstract class, which uses the __call method to provide getProperty, setProperty and addProperty functionality.