Repository: pydantic/pydantic
Pull request: 🐛 Support defining `json_schema_extra` on `RootModel` using `Field`
## Change Summary

Add support for `json_schema_extra` using `Field` on `Root.root`

## Related issue number

Fix #6579

## Checklist

* [x] The pull request title is a good summary of the changes - it will be used in the changelog
* [x] Unit tests for the changes exist
* [x] Tests pass on CI and coverage remains at 100%
* [x] Documentation reflects the changes where applicable
* [x] My PR is ready to review, **please add a comment including the phrase "please review" to assign reviewers**


Selected Reviewer: @dmontagu

Problem statement:
`Field(json_schema_extra=...)` is missing in schema with `RootModel`
### Initial Checks

- [X] I confirm that I'm using Pydantic V2

### Description

`RootModel` ignores `json_schema_extra` in the outputted schema. Breakage from V1 `__root__` which did respect it.

### Example Code

```Python
from pydantic import BaseModel, Field, RootModel

class Foo(BaseModel):
    foo: str = Field(json_schema_extra={"foo": "bar"})

class Bar(RootModel):
    root: str = Field(json_schema_extra={"foo": "bar"})

# Works:
print(Foo.model_json_schema())
# <--- {'properties': {'foo': {'foo': 'bar', 'title': 'Foo', 'type': 'string'}}, 'required': ['foo'], 'title': 'Foo', 'type': 'object'}

# json_schema_extra contents missing:
print(Bar.model_json_schema())
# <--- {'title': 'Bar', 'type': 'string'}
```


### Python, Pydantic & OS Version

```Text
pydantic version: 2.0.2
        pydantic-core version: 2.1.2 release build profile
                 install path: venv/lib/python3.11/site-packages/pydantic
               python version: 3.11.4 (main, Jun  7 2023, 12:45:48) [GCC 11.3.0]
                     platform: Linux-5.19.0-46-generic-x86_64-with-glibc2.35
     optional deps. installed: ['devtools', 'email-validator', 'typing-extensions']
```


Selected Assignee: @Kludex

Hints from issue discussion:

Commit message: 🐛 Support defining `json_schema_extra` on `RootModel` using `Field`

Patch to review:
diff --git a/pydantic/json_schema.py b/pydantic/json_schema.py
index d469840294b..989cef6d9bd 100644
--- a/pydantic/json_schema.py
+++ b/pydantic/json_schema.py
@@ -1256,6 +1256,16 @@ def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue:
         title = config.get('title')
 
         json_schema_extra = config.get('json_schema_extra')
+        if cls.__pydantic_root_model__:
+            root_json_schema_extra = cls.model_fields['root'].json_schema_extra
+            if json_schema_extra and root_json_schema_extra:
+                raise ValueError(
+                    '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"'
+                    ' field could not be set simultaneously'
+                )
+            if root_json_schema_extra:
+                json_schema_extra = root_json_schema_extra
+
         json_schema = self._update_class_schema(json_schema, title, config.get('extra', None), cls, json_schema_extra)
 
         return json_schema
diff --git a/tests/test_root_model.py b/tests/test_root_model.py
index 85884437d31..96d86e8ce6b 100644
--- a/tests/test_root_model.py
+++ b/tests/test_root_model.py
@@ -561,3 +561,35 @@ class MyRootModel(RootModel[str]):
 
     MyRootModel = module.MyRootModel
     assert MyRootModel(root='abc') == pickle.loads(pickle.dumps(MyRootModel(root='abc')))
+
+
+def test_json_schema_extra_on_model():
+    class Model(RootModel):
+        model_config = ConfigDict(json_schema_extra={'schema key': 'schema value'})
+        root: str
+
+    assert Model.model_json_schema() == {
+        'schema key': 'schema value',
+        'title': 'Model',
+        'type': 'string',
+    }
+
+
+def test_json_schema_extra_on_field():
+    class Model(RootModel):
+        root: str = Field(json_schema_extra={'schema key': 'schema value'})
+
+    assert Model.model_json_schema() == {
+        'schema key': 'schema value',
+        'title': 'Model',
+        'type': 'string',
+    }
+
+
+def test_json_schema_extra_on_model_and_on_field():
+    class Model(RootModel):
+        model_config = ConfigDict(json_schema_extra={'schema key on model': 'schema value on model'})
+        root: str = Field(json_schema_extra={'schema key on field': 'schema value on field'})
+
+    with pytest.raises(ValueError, match=r'json_schema_extra.*?could not be set simultaneously'):
+        Model.model_json_schema()


Code review comments:
diff_hunk: @@ -1256,6 +1256,16 @@ def model_schema(self, schema: core_schema.ModelSchema) -> JsonSchemaValue:
         title = config.get('title')
 
         json_schema_extra = config.get('json_schema_extra')
+        if cls.__pydantic_root_model__:
+            root_json_schema_extra = cls.model_fields['root'].json_schema_extra
+            if json_schema_extra and root_json_schema_extra:
+                raise ValueError(
+                    '"model_config[\'json_schema_extra\']" and "Field.json_schema_extra" on "RootModel.root"'
+                    ' field could not be set simultaneously'
path: pydantic/json_schema.py
text: @user1:
```suggestion
                    ' field must not be set simultaneously'
```