---
title: Inject objects into a node instance
description: Use Guice dependency injection to inject objects into authentication node instances in PingAM trees
component: pingam
version: 8
page_id: pingam:auth-nodes:core-inject
canonical_url: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-inject.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
revdate: 2026-07-07T12:28:33Z
keywords: ["Extensibility", "Nodes &amp; Trees", "Scripts"]
superseded_by: https://docs.pingidentity.com/pingam/8.1/auth-nodes/core-inject.html
section_ids:
  using-a-cache: Use a cache
  send-http-request: Send an HTTP request
  custon-guice-bindings: Custom Guice bindings
---

# Inject objects into a node instance

AM constructs a node instance more than once per authentication request: first during the input-collection phase to discover shared and transient state keys, and then during the execution phase to run `process()`. With nested trees (such as when the [Inner Tree Evaluator node](https://docs.pingidentity.com/auth-node-ref/8/inner-tree-evaluator.html) is used), every node in the inner tree has its constructor called twice per request.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Keep constructors lightweight. Only assign injected dependencies to `private final` fields. Never perform the following operations in a constructor:- **Spawning threads** — don't call any `Executors` factory method or instantiate `Thread` objects directly. Inject a Guice-managed `ExecutorService` instead.

- **Network operations** — don't open sockets, perform DNS lookups, initiate TLS handshakes, or set up local connection pools. Inject AM's shared HTTP client (`@Named("CloseableHttpClientHandler") Handler`) or another pre-configured shared client instead.

- **Stateful fields** — keep nodes stateless. Declare all injected components as `private final`. Use `TreeContext` and shared state inside `process()` for request-scoped data.Performing I/O, creating network connections, or spawning threads in a constructor runs on every authentication request and degrades performance or stability. Use `@Singleton` Guice-managed classes for expensive shared resources. Learn more in [Use a cache](#using-a-cache). |

AM uses Google's *Guice* dependency injection framework for authentication nodes and uses Guice to manage most of its object lifecycles. Use *just-in-time* bindings from the constructor to inject an object from Guice.

The following node-specific instances are available from Guice:

* @Assisted Realm

  The realm that the node is in.

* @Assisted UUID

  The unique ID of the node instance.

* @Assisted TreeMetadata

  The metadata for the tree that the node belongs to.

* \<T> @Assisted T

  The configuration object that is an instance of the interface specified in the `configClass` metadata parameter.

|   |                                                                                                     |
| - | --------------------------------------------------------------------------------------------------- |
|   | Any other objects in AM that are managed by Guice can also be obtained from within the constructor. |

The following example is the configuration injection used by the [Debug node](https://docs.pingidentity.com/auth-node-ref/8/am-only/debug.html):

```java
@Inject
public DebugNode(@Assisted DebugNode.Config config) {
  this.config = config;
  ...
}
```

Learn more in the [Inject](https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/Inject.html) and [Assisted](https://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/assistedinject/Assisted.html) annotation types in the *Google Guice Javadoc*.

## Use a cache

You can use Guice injection to cache information in a node by annotating the object that contains the cache with the `@Singleton` annotation.

|   |                                                                                                                                                                                                                                                                           |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The Guice injected singleton will be used by multiple threads, so it must be thread safe. The following example uses the Google `LoadingCache`, which is thread safe. Alternatively, use `java.util.concurrent.ConcurrentMap` if you prefer to use a built-in Java class. |

For example:

```java
@Node.Metadata(
  outcomeProvider = SingleOutcomeNode.OutcomeProvider.class,
  configClass = MyCustomNode.Config.class)
  public class MyCustomNode extends SingleOutcomeNode {

    public interface Config {
      String url();
    }

    private final Config config;
    private final MyCustomNodeCache cache;

    @Inject
    public MyCustomNode(@Assisted Config config, MyCustomNodeCache cache) {
      this.config = config;
      this.cache = cache;
    }

    @Override
    public Action process(TreeContext context) {
      CachedThing thing = cache.getThing(config.url());
      // implement node logic here
    }
}

@Singleton
class MyCustomNodeCache {
   private final LoadingCache<String, CachedThing> cache =
      CacheBuilder.newBuilder()
         .build(CacheLoader.from(url -> read(url)));

   public CachedThing get(String url) {
      return cache.get(url);
   }

   private CachedThing read(String url) {
      // Access resource and construct
   }
}
```

## Send an HTTP request

You can use Guice injection to send an HTTP request by injecting the `CloseableHttpClientHandler` into the node instance. This means the node uses the standard AM HTTP client handler, and all the httpClient settings and tuning apply.

The following example demonstrates sending an HTTP POST request to the `https://www.example.com/api` endpoint:

```java
@Inject
public MyCustomNode(@Named("CloseableHttpClientHandler") Handler httpClientHandler) {
  this.httpClientHandler = httpClientHandler;
}

@Override
public Action process(TreeContext context) {
   URI uri = URI.create("https://www.example.com/api");

   Request request = new Request()
           .setUri(uri)
           .setMethod(HttpConstants.Methods.POST);

   JsonValue body = json(object(field("sampleKey", "sampleValue")));
   request.getEntity().setJson(body);

   Response response = httpClientHandler.handle(new RootContext(), request).getOrThrow();
}
```

## Custom Guice bindings

If just-in-time bindings aren't sufficient for your use case, you can add your own Guice module into the injector configuration by implementing your own `com.google.inject.Module` and registering it using the service loader mechanism. For example:

```java
// com/example/MyCustomModule.java
public class MyCustomModule extends AbstractModule {
   @Override
   protected void configure() {
      bind(Thing.class).to(MyThing.class);
      // and so on
   }
}
```

```java
// META-INF/services/com.google.inject.Module
// Learn more in https://docs.oracle.com/javase/tutorial/ext/basics/spi.html
com.example.MyCustomModule
```

The `MyCustomModule` object will then be automatically configured as part of the injector creation.
