# getProviderObject method

1. @protected

Future<ObjectHolder<Object>> getProviderObject(

1. PodProvider provider,
2. Class? type,
3. String name,
4. bool shouldPostProcess,

)

Retrieves the object managed by a PodProvider, applying caching and optional post-processing semantics.

This method encapsulates the complete retrieval lifecycle for provider-based pods, balancing performance (fast cached return) and correctness (safe singleton initialization and decoration).

# Retrieval Flow

1. Fast path: cache hit

   - If a raw ObjectHolder is already cached in podProviderInstanceCache, return it directly.
   - If `shouldPostProcess` is `true`, and the singleton is not currently being created, apply postProcessObjectFromPodProvider on-the-fly without overwriting the raw cache.

2. Singleton path: uncached

   - If the provider is a singleton and `containsSingleton` reports that the registry knows the name, invoke `_doGet` to retrieve the raw object.
   - If another thread/path cached the object while awaiting, prefer the cached one and apply optional post-processing.
   - Cache only the raw object, never the post-processed variant.

3. Non-singleton path

   - For prototype or non-registered providers, call `_doGet` each time.
   - Apply optional post-processing immediately; no caching is performed.

# Error Handling

- Wraps any post-processing errors into PodCreationException.
- Protects against circular singleton creation by skipping post-processing when `isCurrentlyCreatingSingleton` is true.

# Parameters

- `provider`: The PodProvider to query.
- `type`: The expected type (may be `null`).
- `name`: The logical pod name.
- `shouldPostProcess`: If `true`, applies postProcessObjectFromPodProvider before returning.

# Returns

- An ObjectHolder wrapping the resolved object.
- Will never return `null`, but may wrap a NullablePod.

# Throws

- PodCreationException if post-processing fails.
- Other exceptions surfaced by `_doGet`.

# Notes

- The raw instance cache always stores unprocessed objects.
- Post-processing is transient, applied per-request, and never cached.

## Implementation

    @protected
    Future<ObjectHolder<Object>> getProviderObject(PodProvider provider, Class? type, String name, bool shouldPostProcess) async {
      // Fast path: if cached raw object exists, return it (or a processed view) without calling provider.
      final ObjectHolder<Object>? cached = podProviderInstanceCache[name];
      if (cached != null) {
        if (!shouldPostProcess) {
          return cached;
        }

        // Caller wants a post-processed view. If we're currently creating the singleton,
        // don't attempt to post-process — return the raw cached value.
        if (isCurrentlyCreatingSingleton(name)) {
          return cached;
        }

        // Perform post-processing on-the-fly, but DO NOT overwrite the cached raw value.
        beforeSingletonCreation(name);
        try {
          return await postProcessObjectFromPodProvider(cached, name);
        } catch (ex) {
          throw PodCreationException(
            "Post-processing of PodProvider's singleton object failed",
            cause: ex is Throwable ? ex : RuntimeException(ex.toString()),
          );
        } finally {
          afterSingletonCreation(name);
        }
      }

      // No cached raw object. If the provider claims singleton and registry knows about it,
      // get from provider and (by previous behavior) cache the raw result.
      if (provider.isSingleton() && containsSingleton(name)) {
        // Obtain raw object from provider
        ObjectHolder<Object> object = await _doGet(provider, type, name);

        // Another concurrent path may have populated the cache while we awaited — prefer that
        final ObjectHolder<Object>? seen = podProviderInstanceCache[name];
        if (seen != null) {
          // If caller wants post-process, apply it on-the-fly to the seen value
          if (shouldPostProcess) {
            if (isCurrentlyCreatingSingleton(name)) {
              return seen;
            }

            beforeSingletonCreation(name);
            try {
              return await postProcessObjectFromPodProvider(seen, name);
            } catch (ex) {
              throw PodCreationException(
                "Post-processing of PodProvider's singleton object failed",
                cause: ex is Throwable ? ex : RuntimeException(ex.toString()),
              );
            } finally {
              afterSingletonCreation(name);
            }
          }

          return seen;
        }

        // Cache the raw object (maintain previous caching semantics)
        if (containsSingleton(name)) {
          podProviderInstanceCache[name] = object;
        }

        // If post-processing requested, process the raw object on-the-fly and DO NOT overwrite cache.
        if (shouldPostProcess) {
          if (isCurrentlyCreatingSingleton(name)) {
            return object;
          }

          beforeSingletonCreation(name);
          try {
            return await postProcessObjectFromPodProvider(object, name);
          } catch (ex) {
            throw PodCreationException(
              "Post-processing of PodProvider's singleton object failed",
              cause: ex is Throwable ? ex : RuntimeException(ex.toString()),
            );
          } finally {
            afterSingletonCreation(name);
          }
        }

        // No post-processing requested, return the raw cached object
        return object;
      } else {
        // Non-singleton or not registered as singleton: just call provider (no caching)
        ObjectHolder<Object> object = await _doGet(provider, type, name);
        if (shouldPostProcess) {
          try {
            return await postProcessObjectFromPodProvider(object, name);
          } catch (ex) {
            throw PodCreationException(
              "Post-processing of PodProvider's object failed for $name",
              cause: ex is Throwable ? ex : RuntimeException(ex.toString()),
            );
          }
        }

        return object;
      }
    }