# doGet method

1. @protected

Future<Object> doGet(

1. String name,
2. Class<Object>? type,
3. List<ArgumentValue>? args, [
4. bool prototypeInSingleton = false,

])

Main template method for pod retrieval that implements the core resolution algorithm.

This method is the heart of the pod factory system, handling:

1. Pod name transformation and alias resolution
2. Singleton cache lookup
3. Parent factory delegation for hierarchical lookups
4. Dependency resolution and circular dependency detection
5. Scope-based pod creation (singleton, prototype, custom scopes)
6. PodProvider unwrapping and instance creation

Usage Example:

    final pod = await doGet('myService', Class.forObject(MyService), null);

`name` the name of the pod to retrieve `type` the expected type of the pod (optional) `args` constructor arguments for the pod (optional) Returns the retrieved pod instance

Throws PodCurrentlyInCreationException for circular dependencies Throws PodCreationException for pod creation failures

## Implementation

    @protected
    Future<Object> doGet(String name, Class<Object>? type, List<ArgumentValue>? args, [bool prototypeInSingleton = false]) async {
      Object instance;

      final transformed = transformedPodName(name);
      ObjectHolder<Object>? cache = await getSingletonCache(transformed); // Check singleton cache first
      Object? shared = cache?.getValue();

      if (shared != null && args == null && cache != null) {
        if (_logger.getIsTraceEnabled()) {
    				if (isCurrentlyCreatingSingleton(transformed)) {
    					_logger.trace("Returning eagerly cached instance of singleton pod '$transformed' that is not fully initialized yet - a consequence of a circular reference");
    				} else {
    					_logger.trace("Returning cached instance of singleton pod '$transformed'");
    				}
    			}

        instance = await doGetObject(shared, type, name, transformed, null);
      } else {
        // Fail if we're already creating this pod instance: We're assumably within a circular reference.
    			if (isCurrentlyCreatingPrototype(transformed)) {
    				throw PodCurrentlyInCreationException(name: transformed);
    			}

        // Check if pod definition exists in this provider.
    			PodFactory? parent = getParentFactory();

        if (parent != null && !containsDefinition(transformed)) {
    				String lookup = PodUtils.originalName(name); // Not found -> check parent.

    				if (parent is AbstractPodFactory) {
    					return await parent.doGet(lookup, type, args);
    				} else if (args != null) { // Delegation to parent with explicit args.
    					if (type == null) {
              return await parent.getPod(lookup, args);
            } else {
              return await parent.get(type, args);
            }
    				} else { // No args -> delegate to standard getPod method.
            if (type != null) {
              return await parent.get(type);
            }
    					return await parent.getPod(lookup);
    				}
    			} else {
          markPodAsCreated(transformed);

          StartupStep createStep = _applicationStartup.start(STARTUP_STEP_INSTANTIATE_POD).tag("name", value: name);

          try {
            if (type != null) {
              createStep.tag("podType", value: type.toString());
            }

            final merged = getLocalMergedPodDefinition(transformed);
            type ??= Class.fromQualifiedName<Object>(merged.type.getQualifiedName());

            checkMergedPodDefinition(merged, transformed, args);

            // Guarantee initialization of pods that the current pod depends on.
            List<DependencyDesign> dependsOn = merged.dependsOn;
            if (dependsOn.isNotEmpty) {
              for (DependencyDesign dep in dependsOn) {
                final depName = dep.name;
                if(depName == null) {
                  continue;
                }

                if (isDependent(transformed, depName)) {
                  throw PodCreationException.withResource(
                    merged.description,
                    transformed,
                    "Circular depends-on relationship between '$transformed' and '$dep'"
                  );
                }

                registerDependentPod(depName, transformed);
                try {
                  await doGet(depName, null, null, dep.prototypeInSingleton);
                } on NoSuchPodDefinitionException catch (ex) {
                  throw PodCreationException.withResource(
                    merged.description,
                    transformed,
                    "$transformed depends on missing pod $dep",
                    cause: ex
                  );
                } on PodCreationException catch (ex) {
                  throw PodCreationException.withResource(
                    merged.description,
                    transformed,
                    "Failed to initialize dependency '${(ex.getPodName() ?? "")}' of ${type.getSimpleName()} pod '$transformed'",
                    cause: ex
                  );
                }
              }
            }

            // If a pod instance is already available, return it.
            if (merged.instance != null) {
              if (type.isInstance(merged.instance)) {
                return convertIfNecessary(name, merged.instance!, type);
              } else if (merged.type.isInstance(merged.instance)) {
                return convertIfNecessary(name, merged.instance!, merged.type);
              }
            }

            // Create pod instance
            if (merged.scope.isSingleton && !prototypeInSingleton) {
              final create = () async {
                try {
                  return ObjectHolder(
                    await doCreate(transformed, merged, args),
                    packageName: type?.getPackage()?.getName(),
                    qualifiedName: type?.getQualifiedName()
                  );
                } on PodException catch (_) {
                  // Explicitly remove instance from singleton cache: It might have been put there
                  // eagerly by the creation process, to allow for circular reference resolution.
                  // Also remove any pods that received a temporary reference to the pod.
                  destroySingleton(transformed);
                  rethrow;
                }
              };

              final creator = SimpleObjectFactory<Object>(([args]) async => create());
              shared = await getSingleton(transformed, factory: creator);

              if (shared == null) {
                throw PodCreationException.withResource(
                  merged.description,
                  transformed,
                  "Failed to create singleton pod '$transformed'"
                );
              }

              instance = await doGetObject(shared, type, name, transformed, merged);
            } else if (merged.scope.isPrototype || prototypeInSingleton) {
              // It's a prototype -> create a new instance.
              Object prototype;
              try {
                beforePrototypeCreation(transformed);
                prototype = await doCreate(transformed, merged, args);
              } finally {
                afterPrototypeCreation(transformed);
              }

              instance = await doGetObject(prototype, type, name, transformed, merged);
            } else {
              final scopeName = merged.scope.type;

              if (scopeName.isEmpty) {
                throw IllegalStateException("No scope name defined for pod '$transformed'");
              } else {
                final scope = _scopes[scopeName];
                if (scope == null) {
                  throw PodException('No Scope registered for scope name: $scopeName');
                } else {
                  try {
                    final create = () async {
                      beforePrototypeCreation(transformed);

                      try {
                        return ObjectHolder(
                          await doCreate(transformed, merged, args),
                          packageName: type?.getPackage()?.getName(),
                          qualifiedName: type?.getQualifiedName()
                        );
                      } finally {
                        afterPrototypeCreation(transformed);
                      }
                    };

                    final result = await scope.get(transformed, SimpleObjectFactory(([args]) async => create()));
                    shared = result.getValue();

                    instance = await doGetObject(result.getValue(), type, name, transformed, merged);
                  } on IllegalStateException catch (ex) {
                    throw ScopeNotActiveException(transformed, scopeName, ex);
                  }
                }
              }
            }
          } on PodException catch (ex) {
            createStep.tag("exception", value: ex.getClass().toString());
            createStep.tag("message", value: ex.getMessage());
            cleanupAfterPodCreationFailure(transformed);
            rethrow;
          } finally {
            createStep.end();
            if (!isCachePodMetadata()) {
              clearMergedPodDefinition(transformed);
            }
          }
        }
      }

      return convertIfNecessary(name, instance, type);
    }