Problem/Motivation
ListNormalizer does not opt in to the json_schema format, so Serializer::getJsonSchema() returns a placeholder for every ListInterface object. See the change record for the JSON Schema support added to the serializer.
A list's schema is the schema of its item definition wrapped in an array. ListDataDefinitionInterface::getItemDefinition() already provides the item definition, so core has everything it needs.
The schema has to come from the item definition, not the list's items. ListNormalizer::normalize() iterates the items it holds, and an empty list holds none.
Steps to reproduce
$list = \Drupal::typedDataManager()->create(ListDataDefinition::create('string'));
\Drupal::service('serializer')->getJsonSchema($list, []);
// ['$comment' => 'No schema is defined for property of type Drupal\Core\TypedData\Plugin\DataType\ItemList. ...']
Expected:
[
'type' => 'array',
'items' => ['oneOf' => [['type' => 'string'], ['type' => 'null']]],
]
Proposed resolution
Add SchematicNormalizerHelperTrait to ListNormalizer. Create an item from the list's item definition and ask the serializer for its schema.
Create the item with TypedDataManagerInterface::getPropertyInstance(), the same way ItemList::createItem() does. The item then has the list as its parent, which field items need. ListNormalizer has no typed data manager today, so it needs one injected.
JSON:API's FieldNormalizer::getNormalizationSchema() solves the same problem by appending an item from generateSampleItems() and removing it afterward. getPropertyInstance() avoids changing the list.
protected function getNormalizationSchema(mixed $object, array $context = []): array {
if (!$object instanceof ListInterface) {
return ['$comment' => static::generateNoSchemaAvailableMessage($object)];
}
$item = $this->typedDataManager->getPropertyInstance($object, 0);
return [
'type' => 'array',
'items' => $this->serializer->getJsonSchema($item, $context),
];
}
Open questions:
- Should
FieldNormalizersetminItemsandmaxItemsfrom the field's cardinality? JSON:API'sFieldNormalizersetsminItems: 1for required fields andmaxItemsfor limited cardinality.ListDataDefinitionhas no cardinality, so plain lists would not change. FieldNormalizerextendsListNormalizerand would inherit the opt-in. A field item list would produce an array of field item schemas. Each item schema depends on howFieldItemNormalizerhandlesjson_schema, which is an open question in [#NNNNNNN].
Remaining tasks
- Decide whether
FieldNormalizeris in scope. - Inject the typed data manager into
ListNormalizerwith a BC layer for subclasses. - Merge request with test coverage.
User interface changes
None.
Introduced terminology
None.
API changes
ListNormalizer supports the json_schema format. Its constructor gains a TypedDataManagerInterface argument. Normalization output does not change.
Data model changes
None.
Release notes snippet
AI-Generated: Yes. I used Claude Code to turn my notes into this issue summary and to check the proposed resolution against the Drupal 11.4.6 source. I reviewed and edited the result. The proposed code is a sketch and has not been run.
Comments
Comment #2
mglamanComment #3
mglaman