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 FieldNormalizer set minItems and maxItems from the field's cardinality? JSON:API's FieldNormalizer sets minItems: 1 for required fields and maxItems for limited cardinality. ListDataDefinition has no cardinality, so plain lists would not change.
  • FieldNormalizer extends ListNormalizer and would inherit the opt-in. A field item list would produce an array of field item schemas. Each item schema depends on how FieldItemNormalizer handles json_schema, which is an open question in [#NNNNNNN].

Remaining tasks

  • Decide whether FieldNormalizer is in scope.
  • Inject the typed data manager into ListNormalizer with 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

mglaman created an issue. See original summary.

mglaman’s picture

Issue summary: View changes
mglaman’s picture

Issue tags: +rosetta