Class Attribute<T>
- Type Parameters:
T- the Java value type stored in the Attribute
Declare Attributes once on the Flow, include them in its PersistenceSchema, and use
the same object from Step and RPC code. Values are serialized using the Class supplied at
definition time. A parameterized value type such as List<String> cannot be supplied
directly because List.class does not retain its element type. Wrap the value in a
concrete class whose field is a List<String>, or use String[] when an array fits
the data model.
private final Attribute<Integer> counter =
Attribute.define("counter", Integer.class);
private final Attribute<Tags> tags =
Attribute.define("tags", Tags.class);
private final Attribute<String[]> tagArray =
Attribute.define("tag-array", String[].class);
static final class Tags {
public List<String> values;
}
public StepDecision execute(Context context, Command input) {
counter.set(context, counter.get(context) + 1);
return StepDecision.gracefulComplete();
}
-
Method Summary
Modifier and TypeMethodDescriptionstatic <T> Attribute<T> Defines an Attribute without a search index.static <T> Attribute<T> define(String name, Class<T> valueType, AttributeIndex index) Defines an Attribute with a search index.voidDeletes this Attribute in the current invocation.Reads this Attribute from the current invocation.Returns a definition whose value is stored only in the Dex blob store and is permanently deleted when the Attribute is deleted or set tonull.voidWrites this Attribute in the current invocation.Returns a definition whose writes are projected through the Flow's Attribute Store.
-
Method Details
-
define
Defines an Attribute without a search index.- Type Parameters:
T- the Java value type- Parameters:
name- the stable Attribute name; must not be blank or contain/valueType- the concrete Java class used to serialize and deserialize values- Returns:
- the typed Attribute definition
- Throws:
IllegalArgumentException- ifnameisnull, blank, or contains/NullPointerException- ifvalueTypeisnull
-
define
Defines an Attribute with a search index.- Type Parameters:
T- the Java value type- Parameters:
name- the stable Attribute name; must not be blank or contain/valueType- the concrete Java class used to serialize and deserialize valuesindex- the search-index definition, ornullfor no index- Returns:
- the typed Attribute definition
- Throws:
IllegalArgumentException- ifnameisnull, blank, or contains/NullPointerException- ifvalueTypeisnull
-
syncToAttributeStore
Returns a definition whose writes are projected through the Flow's Attribute Store.The projection is asynchronous and latest-state only. A projection failure does not roll back the Flow Attribute. Deleting this Attribute projects SQL
NULLwhen the target column permits it.- Returns:
- a new immutable Attribute definition with Attribute Store synchronization enabled
- Throws:
IllegalStateException- if this definition useshardDeleteOnNull()
-
hardDeleteOnNull
Returns a definition whose value is stored only in the Dex blob store and is permanently deleted when the Attribute is deleted or set tonull.Use this option for short-lived secrets, such as an API key or an access token, that a Flow needs for a limited time. A regular Attribute value is recorded in Flow history. A hard-delete Attribute value is never recorded in Flow history. Dex stores it only in the blob store and records only a reference in Flow history. Calling
delete(Context)orset(Context, Object)withnullpermanently deletes the stored value. After the deletion, the Attribute reads as absent.Only string and object values are supported. Object values include JSON-mapped classes and
byte[]. Numeric and Boolean value types, such asInteger,Long,Double, andBoolean, are rejected when this option is applied. When the declared value type is broader, such asObjectorNumber, a write whose value maps to a number or a Boolean is rejected when it is written. Writingnullis always allowed.This option cannot be combined with an
AttributeIndexor withsyncToAttributeStore().Client.waitForAttributeMatch(String, Attribute, AttributeMatch, WaitForAttributeOptions)rejects a hard-delete Attribute before it contacts the Server. Use an RPC that reads the Attribute when a caller needs the value.The Dex Server must have an enabled blob store and must support Server protocol version 3 or later. A Step, RPC, StartFlow, or SubFlow start that writes this Attribute fails with
IllegalStateExceptionwhen the negotiated Server protocol is older. The Server rejects the write when its blob store is disabled. Steps and RPC handlers receive the value inline. The SDK never stores a hard-delete value in the localBlobCache.Know these limitations before you store a secret:
- Each Flow keeps one stored copy per Attribute key. Every write overwrites that copy in place.
- A Step or RPC attempt writes or deletes the stored value before Dex commits the attempt's result. A retried attempt, other Steps, and other readers can therefore observe a write or a deletion from an attempt that later failed.
- When concurrent Steps or RPCs write the same key, the final stored value may not be the
value from the last committed write. When the order matters, use a single writer, or
make every Step and RPC that writes the key hold an
AttributeLockon it. A failed locked attempt can still overwrite the value. - A
Client.startFlow(Flow, String, I)call orSubFlow.run(Class, I)start that fails because the Flow ID is already running still overwrites the running Flow's value. With anullinitial value, it deletes the running Flow's value. - Executions that reuse a Flow ID share the stored value.
Client.timeTravel(String, TimeTravelOptions)does not restore a deleted value. A deleted value reads as absent.- A Flow retry or a restarted SubFlow starts from the original initial value. If an earlier run deleted that value, the new run reads it as absent.
- Removing
hardDeleteOnNull()from a definition leaves the stored value in place until Dex removes the Flow. Delete the value with the hard-delete definition first. - A value remains in the blob store until it is deleted, or until Flow retention removes the Flow and blob cleanup runs.
- Blob store backups and bucket versioning can retain copies after deletion. Configure them separately when deleted secrets must not survive.
final class ProviderSyncFlow implements Flow<String> { final Attribute<String> apiKey = Attribute.define("api-key", String.class).hardDeleteOnNull(); private final SyncWithProvider sync = new SyncWithProvider(apiKey); @Override public StepList<String> getSteps() { return StepList.startStep(sync); } @Override public PersistenceSchema getPersistenceSchema() { return PersistenceSchema.of(apiKey); } } final class SyncWithProvider implements Step<String> { private final Attribute<String> apiKey; SyncWithProvider(final Attribute<String> apiKey) { this.apiKey = apiKey; } @Override public StepDecision execute(final Context context, final String accountId) { final String key = apiKey.get(context); ProviderApi.sync(accountId, key); // Permanently delete the secret once it is no longer needed. apiKey.delete(context); return StepDecision.gracefulComplete(); } } // Start the Flow with the secret as an initial Attribute value. client.startFlow( flow, "provider-sync-42", "account-42", StartFlowOptions.newBuilder() .addAttribute(flow.apiKey, System.getenv("PROVIDER_API_KEY")) .build());- Returns:
- a new immutable Attribute definition with hard deletion on
nullenabled - Throws:
IllegalStateException- if this definition has an index, usessyncToAttributeStore(), or declares a numeric or Boolean value type
-
get
-
set
Writes this Attribute in the current invocation.- Parameters:
context- the Step or RPC invocation contextvalue- the typed value to persist;nulldeletes the value- Throws:
IllegalArgumentException- if this is ahardDeleteOnNull()Attribute and the value maps to a number or a Boolean
-
delete
Deletes this Attribute in the current invocation.- Parameters:
context- the Step or RPC invocation context
-