Repository: pydantic/pydantic

Issue:
BaseModel with defer_build breaks with TypeAdapter.
### Initial Checks

- [X] I confirm that I'm using Pydantic V2

### Description

Repeated uses of a `TypeAdapter` with a model breaks when using `defer_build`.

```
Traceback (most recent call last):
  File "/ptest.py", line 40, in <module>
    ta.validate_python({"foo": "str"})
  File "/venv/lib/python3.11/site-packages/pydantic/type_adapter.py", line 283, in validate_python
    return self.validator.validate_python(__object, strict=strict, from_attributes=from_attributes, context=context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.11/site-packages/pydantic/_internal/_mock_val_ser.py", line 47, in __getattr__
    raise PydanticUserError(self._error_message, code=self._code)
pydantic.errors.PydanticUserError: `Foo` is not fully defined; you should define all referenced types, then call `Foo.model_rebuild()`.

For further information visit **https://errors.pydantic.dev/2.4/u/class-not-fully-defined**
```

### Example Code

```Python
from pydantic import BaseModel, TypeAdapter

class Foo(BaseModel):
    foo: str
    model_config = {
        "defer_build": True,
    }


ta = TypeAdapter(Foo)
ta.validate_python({"foo": "str"})
ta.validate_python({"foo": "str"}) # <--- Second call breaks
```


### Python, Pydantic & OS Version

```Text
pydantic version: 2.4.2
        pydantic-core version: 2.10.1
          pydantic-core build: profile=release pgo=true
                 install path: /venv/lib/python3.11/site-packages/pydantic
               python version: 3.11.5 (main, Aug 25 2023, 13:19:50) [GCC 11.4.0]
                     platform: Linux-6.2.0-33-generic-x86_64-with-glibc2.35
             related packages: email-validator-2.0.0 mypy-1.5.1 fastapi-0.103.2 typing_extensions-4.8.0
```



Discussion:
Thanks for the report. Yeah, it does look like a bug.

Resolving patch:
diff --git a/pydantic/_internal/_dataclasses.py b/pydantic/_internal/_dataclasses.py
--- a/pydantic/_internal/_dataclasses.py
+++ b/pydantic/_internal/_dataclasses.py
@@ -27,7 +27,7 @@
 from ._fields import collect_dataclass_fields
 from ._generate_schema import GenerateSchema
 from ._generics import get_standard_typevars_map
-from ._mock_val_ser import set_dataclass_mock_validator
+from ._mock_val_ser import set_dataclass_mocks
 from ._schema_generation_shared import CallbackGetCoreSchemaHandler
 from ._utils import is_valid_identifier
 
@@ -153,14 +153,14 @@ def __init__(__dataclass_self__: PydanticDataclass, *args: Any, **kwargs: Any) -
     except PydanticUndefinedAnnotation as e:
         if raise_errors:
             raise
-        set_dataclass_mock_validator(cls, cls.__name__, f'`{e.name}`')
+        set_dataclass_mocks(cls, cls.__name__, f'`{e.name}`')
         return False
 
     core_config = config_wrapper.core_config(cls)
 
     schema = gen_schema.collect_definitions(schema)
     if collect_invalid_schemas(schema):
-        set_dataclass_mock_validator(cls, cls.__name__, 'all referenced types')
+        set_dataclass_mocks(cls, cls.__name__, 'all referenced types')
         return False
 
     schema = _discriminated_union.apply_discriminators(simplify_schema_references(schema))
diff --git a/pydantic/_internal/_mock_val_ser.py b/pydantic/_internal/_mock_val_ser.py
--- a/pydantic/_internal/_mock_val_ser.py
+++ b/pydantic/_internal/_mock_val_ser.py
@@ -70,7 +70,7 @@ def set_model_mocks(cls: type[BaseModel], cls_name: str, undefined_name: str = '
     )
 
     def attempt_rebuild_validator() -> SchemaValidator | None:
-        if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5):
+        if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False:
             return cls.__pydantic_validator__
         else:
             return None
@@ -83,7 +83,7 @@ def attempt_rebuild_validator() -> SchemaValidator | None:
     )
 
     def attempt_rebuild_serializer() -> SchemaSerializer | None:
-        if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5):
+        if cls.model_rebuild(raise_errors=False, _parent_namespace_depth=5) is not False:
             return cls.__pydantic_serializer__
         else:
             return None
@@ -96,16 +96,25 @@ def attempt_rebuild_serializer() -> SchemaSerializer | None:
     )
 
 
-def set_dataclass_mock_validator(cls: type[PydanticDataclass], cls_name: str, undefined_name: str) -> None:
+def set_dataclass_mocks(
+    cls: type[PydanticDataclass], cls_name: str, undefined_name: str = 'all referenced types'
+) -> None:
+    """Set `__pydantic_validator__` and `__pydantic_serializer__` to `MockValSer`s on a dataclass.
+
+    Args:
+        cls: The model class to set the mocks on
+        cls_name: Name of the model class, used in error messages
+        undefined_name: Name of the undefined thing, used in error messages
+    """
+    from ..dataclasses import rebuild_dataclass
+
     undefined_type_error_message = (
         f'`{cls_name}` is not fully defined; you should define {undefined_name},'
         f' then call `pydantic.dataclasses.rebuild_dataclass({cls_name})`.'
     )
 
-    def attempt_rebuild() -> SchemaValidator | None:
-        from ..dataclasses import rebuild_dataclass
-
-        if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5):
+    def attempt_rebuild_validator() -> SchemaValidator | None:
+        if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False:
             return cls.__pydantic_validator__
         else:
             return None
@@ -114,5 +123,18 @@ def attempt_rebuild() -> SchemaValidator | None:
         undefined_type_error_message,
         code='class-not-fully-defined',
         val_or_ser='validator',
-        attempt_rebuild=attempt_rebuild,
+        attempt_rebuild=attempt_rebuild_validator,
+    )
+
+    def attempt_rebuild_serializer() -> SchemaSerializer | None:
+        if rebuild_dataclass(cls, raise_errors=False, _parent_namespace_depth=5) is not False:
+            return cls.__pydantic_serializer__
+        else:
+            return None
+
+    cls.__pydantic_serializer__ = MockValSer(  # type: ignore[assignment]
+        undefined_type_error_message,
+        code='class-not-fully-defined',
+        val_or_ser='validator',
+        attempt_rebuild=attempt_rebuild_serializer,
     )


Test patch:
diff --git a/tests/test_config.py b/tests/test_config.py
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -687,6 +687,25 @@ class MyModel(BaseModel, defer_build=True):
     assert isinstance(MyModel.__pydantic_serializer__, SchemaSerializer)
 
 
+def test_config_type_adapter_defer_build():
+    class MyModel(BaseModel, defer_build=True):
+        x: int
+
+    ta = TypeAdapter(MyModel)
+
+    assert isinstance(ta.validator, MockValSer)
+    assert isinstance(ta.serializer, MockValSer)
+
+    m = ta.validate_python({'x': 1})
+    assert m.x == 1
+    m2 = ta.validate_python({'x': 2})
+    assert m2.x == 2
+
+    # in the future, can reassign said validators to the TypeAdapter
+    assert isinstance(MyModel.__pydantic_validator__, SchemaValidator)
+    assert isinstance(MyModel.__pydantic_serializer__, SchemaSerializer)
+
+
 def test_config_model_defer_build_nested():
     class MyNestedModel(BaseModel, defer_build=True):
         x: int