You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Config.GetObject<T>/RequireObject<T>/GetSecretObject<T>/RequireSecretObject<T> deserialize a JSON config value via System.Text.Json.JsonSerializer.Deserialize<T>. This works for plain POCOs, but fails for the pattern commonly used for typed resource arguments, where properties are Input<T>/Output<T> instead of the raw type:
Calling config.RequireObject<GitHubAppArgs>("github") today throws, because System.Text.Json has no converter registered that knows how to construct an Input<string>/Output<string> from a plain JSON string/number/bool.
Add a JsonConverterFactory (and per-type JsonConverter<Input<T>> / JsonConverter<Output<T>>) that:
Reads the underlying JSON value for the wrapped type T using the normal JsonSerializer conversion for T.
Wraps the resulting value as Input<T>/Output<T> (config values are always known/resolved at this point — there is no "unknown" sentinel needed, unlike the policy-engine's serialization path, since config is never used to represent an in-flight resource output).
Is registered by default for the existing *Object config methods (GetObject, RequireObject, GetSecretObject, RequireSecretObject), so no explicit opt-in is required for the common case.
Open questions to resolve during design/implementation
Secrets propagation: RequireSecretObject<T>/GetSecretObject<T> currently wrap the entire deserialized object in a single outer Output.CreateSecret(...). If a nested property is itself an Output<T> produced by the new converter, does it also need to be marked secret, or is the outer wrapping sufficient? (Likely the outer wrapping is sufficient since the whole object is already secret, but this should be explicit in tests/docs.)
Collections and nesting: needs to work for Input<T> inside plain properties, and ideally for common nested cases (e.g. Input<T> inside a List<T> or nested ResourceArgs-shaped class), not just top-level scalar properties.
Unsupported/ambiguous shapes: decide behavior when T itself doesn't support the required JsonSerializer conversion (should surface the existing ConfigTypeException, same as today for other failures).
This is a genuinely new feature (a custom converter + default wiring), not a bug fix, and changes the shape of what types can be round-tripped through Config deserialization. It deserves its own design discussion and test plan rather than being bundled into the original report, which was mostly about the base case (already working) and the unrelated JsonSerializerOptions ask (tracked in #370).
Summary
Config.GetObject<T>/RequireObject<T>/GetSecretObject<T>/RequireSecretObject<T>deserialize a JSON config value viaSystem.Text.Json.JsonSerializer.Deserialize<T>. This works for plain POCOs, but fails for the pattern commonly used for typed resource arguments, where properties areInput<T>/Output<T>instead of the raw type:Calling
config.RequireObject<GitHubAppArgs>("github")today throws, becauseSystem.Text.Jsonhas no converter registered that knows how to construct anInput<string>/Output<string>from a plain JSON string/number/bool.Originally raised by @jzebedee in #17.
Proposed scope
Add a
JsonConverterFactory(and per-typeJsonConverter<Input<T>>/JsonConverter<Output<T>>) that:Tusing the normalJsonSerializerconversion forT.Input<T>/Output<T>(config values are always known/resolved at this point — there is no "unknown" sentinel needed, unlike the policy-engine's serialization path, since config is never used to represent an in-flight resource output).*Objectconfig methods (GetObject,RequireObject,GetSecretObject,RequireSecretObject), so no explicit opt-in is required for the common case.Open questions to resolve during design/implementation
RequireSecretObject<T>/GetSecretObject<T>currently wrap the entire deserialized object in a single outerOutput.CreateSecret(...). If a nested property is itself anOutput<T>produced by the new converter, does it also need to be marked secret, or is the outer wrapping sufficient? (Likely the outer wrapping is sufficient since the whole object is already secret, but this should be explicit in tests/docs.)JsonSerializerOptionsinteraction: Allow customization of JsonSerializationOptions #370 / PR Extending Config class to support passing JsonSerializerOptions #373 adds support for passing customJsonSerializerOptionsinto the*Objectmethods. The newInput<T>/Output<T>converter should compose with caller-supplied options (i.e. added as one converter among others, not something that requires replacing the whole options object) rather than conflicting with that work.Input<T>inside plain properties, and ideally for common nested cases (e.g.Input<T>inside aList<T>or nestedResourceArgs-shaped class), not just top-level scalar properties.Titself doesn't support the requiredJsonSerializerconversion (should surface the existingConfigTypeException, same as today for other failures).Why this is separate from #17
This is a genuinely new feature (a custom converter + default wiring), not a bug fix, and changes the shape of what types can be round-tripped through
Configdeserialization. It deserves its own design discussion and test plan rather than being bundled into the original report, which was mostly about the base case (already working) and the unrelatedJsonSerializerOptionsask (tracked in #370).References
JsonSerializerOptions)sdk/Pulumi/Config.cs(GetObjectImpl<T>,RequireObjectImpl<T>,GetSecretObject<T>,RequireSecretObject<T>)