From 3b48778a6554bf009eb461651bc32b8341d3416f Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Mon, 24 Aug 2020 17:12:25 +0200 Subject: [PATCH] fix(kernel): calling super.property unexpectedly returns `undefined` (#1932) When overriding a property, the `@jsii/kernel` creates a shadow property for the previous implementation. In order to preserve the existing implementation (whether the property is dynamic or not), the property descriptor is retrieved and re-declared with the new name. This process did not crawl up the prototype chain, and only looked at the object itself. In many cases, this will never return anything (since `Object.getOwnPropertyDescriptor` will not return inherited descriptors) and in this case the `undefined` value was always used. This would break whenever attempting to override a property that was inherited from a parent class, and appears to fail with certain `node` runtimes where the dynamic properties are set on the object's prototype and not on the object itself. This change adds the necessary logic to traverse the prototype chain all the way up to `Object` (not included), to locate the property descriptor and upon failing to identify one, uses the current value of the property instead of `undefined`. --- packages/@jsii/kernel/lib/kernel.ts | 20 +- packages/@jsii/kernel/package.json | 8 +- packages/@jsii/kernel/test/kernel.test.ts | 63 +++ packages/@jsii/runtime/package.json | 8 +- ....test.js.snap => kernel-host.test.ts.snap} | 0 packages/@jsii/runtime/test/playback.test.ts | 2 +- packages/jsii-calc/lib/compliance.ts | 33 ++ packages/jsii-calc/test/assembly.jsii | 138 ++++- .../__snapshots__/jsii-pacmak.test.ts.snap | 523 +++++++++++++++++- .../test/__snapshots__/jsii-tree.test.js.snap | 40 ++ .../__snapshots__/type-system.test.js.snap | 2 + 11 files changed, 828 insertions(+), 9 deletions(-) rename packages/@jsii/runtime/test/__snapshots__/{kernel-host.test.js.snap => kernel-host.test.ts.snap} (100%) diff --git a/packages/@jsii/kernel/lib/kernel.ts b/packages/@jsii/kernel/lib/kernel.ts index 0c658bf5b2..cc42ddedfb 100644 --- a/packages/@jsii/kernel/lib/kernel.ts +++ b/packages/@jsii/kernel/lib/kernel.ts @@ -612,8 +612,8 @@ export class Kernel { // save the old property under $jsii$super$$ so that property overrides // can still access it via `super.`. - const prev = Object.getOwnPropertyDescriptor(obj, propertyName) ?? { - value: undefined, + const prev = getPropertyDescriptor(obj, propertyName) ?? { + value: obj[propertyName], writable: true, enumerable: true, configurable: true, @@ -656,6 +656,22 @@ export class Kernel { }); }, }); + + function getPropertyDescriptor( + obj: any, + propertyName: string, + ): PropertyDescriptor | undefined { + const direct = Object.getOwnPropertyDescriptor(obj, propertyName); + if (direct != null) { + return direct; + } + const proto = Object.getPrototypeOf(obj); + if (proto == null && proto !== Object.prototype) { + // We reached Object or the prototype chain root, all hope is lost! + return undefined; + } + return getPropertyDescriptor(proto, propertyName); + } } private _applyMethodOverride( diff --git a/packages/@jsii/kernel/package.json b/packages/@jsii/kernel/package.json index cbd7711aec..7e4e832949 100644 --- a/packages/@jsii/kernel/package.json +++ b/packages/@jsii/kernel/package.json @@ -50,6 +50,7 @@ "jsii-build-tools": "^0.0.0", "jsii-calc": "^0.0.0", "prettier": "^2.0.5", + "ts-jest": "^26.2.0", "typescript": "~3.9.7" }, "jest": { @@ -73,7 +74,10 @@ ], "testEnvironment": "node", "testMatch": [ - "**/?(*.)+(spec|test).js" - ] + "**/?(*.)+(spec|test).ts" + ], + "transform": { + "\\.tsx?$": "ts-jest" + } } } diff --git a/packages/@jsii/kernel/test/kernel.test.ts b/packages/@jsii/kernel/test/kernel.test.ts index 59d20f3a23..31f7d2ff1e 100644 --- a/packages/@jsii/kernel/test/kernel.test.ts +++ b/packages/@jsii/kernel/test/kernel.test.ts @@ -2066,6 +2066,69 @@ defineTest('ANY serializer: ref', (sandbox) => { }); }); +defineTest('Override transitive property', (sandbox) => { + ////////// + // GIVEN + ////////// + const originalString = 'r00t'; + const initialOverriddenPropValue = 'Overridden Value'; + let propValue = initialOverriddenPropValue; + sandbox.callbackHandler = makeSyncCallbackHandler((callback) => { + const getOrSet = callback.get ?? callback.set; + // We don't expect to receive any other callback + expect(getOrSet).toBeDefined(); + expect(getOrSet?.property).toBe('dynamicProperty'); + + if (callback.get) { + return propValue; + } + propValue = callback.set?.value; + return void 0; + }); + + ////////// + // WHEN + ////////// + const objref = sandbox.create({ + fqn: 'jsii-calc.DynamicPropertyBearerChild', + args: [originalString], + overrides: [{ property: 'dynamicProperty' }], + }); + + ////////// + // THEN + ////////// + + // Reading the "super" property + expect(sandbox.get({ objref, property: 'dynamicProperty' }).value).toBe( + originalString, + ); + expect(sandbox.get({ objref, property: 'valueStore' }).value).toBe( + originalString, + ); + + // Setting the dynamicProperty value through the override + expect( + sandbox.invoke({ objref, method: 'overrideValue', args: ['N3W'] }).result, + ).toBe(initialOverriddenPropValue); + // Checking the side effect happened on the override: + expect(propValue).toBe('N3W'); + // Check the "super" property didn't change: + expect(sandbox.get({ objref, property: 'dynamicProperty' }).value).toBe( + originalString, + ); + expect(sandbox.get({ objref, property: 'valueStore' }).value).toBe( + originalString, + ); + + // Set the "super" property now + sandbox.set({ objref, property: 'dynamicProperty', value: '' }); + // Check the side effect made it to the storage + expect(sandbox.get({ objref, property: 'valueStore' }).value).toBe(''); + // Check the overridden property didn't change... + expect(propValue).toBe('N3W'); +}); + // ================================================================================================= const testNames: { [name: string]: boolean } = {}; diff --git a/packages/@jsii/runtime/package.json b/packages/@jsii/runtime/package.json index 5ea1312677..a13a379418 100644 --- a/packages/@jsii/runtime/package.json +++ b/packages/@jsii/runtime/package.json @@ -49,6 +49,7 @@ "prettier": "^2.0.5", "source-map": "^0.7.3", "source-map-loader": "^1.0.2", + "ts-jest": "^26.2.0", "typescript": "~3.9.7", "wasm-loader": "^1.3.0", "webpack": "^4.44.1", @@ -76,7 +77,10 @@ ], "testEnvironment": "node", "testMatch": [ - "**/?(*.)+(spec|test).js" - ] + "**/?(*.)+(spec|test).ts" + ], + "transform": { + "\\.tsx?$": "ts-jest" + } } } diff --git a/packages/@jsii/runtime/test/__snapshots__/kernel-host.test.js.snap b/packages/@jsii/runtime/test/__snapshots__/kernel-host.test.ts.snap similarity index 100% rename from packages/@jsii/runtime/test/__snapshots__/kernel-host.test.js.snap rename to packages/@jsii/runtime/test/__snapshots__/kernel-host.test.ts.snap diff --git a/packages/@jsii/runtime/test/playback.test.ts b/packages/@jsii/runtime/test/playback.test.ts index 0a62fb701e..fed5cbba51 100644 --- a/packages/@jsii/runtime/test/playback.test.ts +++ b/packages/@jsii/runtime/test/playback.test.ts @@ -42,7 +42,7 @@ function createRecords(): string { ...process.execArgv, require.resolve('jest/bin/jest'), '--coverage=false', - 'test/kernel.test.js', + 'test/kernel.test.ts', ], { env: { ...process.env, JSII_RECORD: records, JSII_NOSTACK: '1' }, diff --git a/packages/jsii-calc/lib/compliance.ts b/packages/jsii-calc/lib/compliance.ts index bf83ed4e3b..2163f680b8 100644 --- a/packages/jsii-calc/lib/compliance.ts +++ b/packages/jsii-calc/lib/compliance.ts @@ -2786,3 +2786,36 @@ export abstract class BurriedAnonymousObject { } import { StaticConsumer } from '@scope/jsii-calc-base-of-base'; + +/** + * Ensures we can override a dynamic property that was inherited. + */ +export class DynamicPropertyBearer { + public constructor(public valueStore: string) {} + + public get dynamicProperty(): string { + return this.valueStore; + } + + public set dynamicProperty(value: string) { + this.valueStore = value; + } +} +export class DynamicPropertyBearerChild extends DynamicPropertyBearer { + public constructor(public readonly originalValue: string) { + super(originalValue); + } + + /** + * Sets `this.dynamicProperty` to the new value, and returns the old value. + * + * @param newValue the new value to be set. + * + * @returns the old value that was set. + */ + public overrideValue(newValue: string): string { + const oldValue = this.dynamicProperty; + this.dynamicProperty = newValue; + return oldValue; + } +} diff --git a/packages/jsii-calc/test/assembly.jsii b/packages/jsii-calc/test/assembly.jsii index 8611ff803f..ac9fd2e83a 100644 --- a/packages/jsii-calc/test/assembly.jsii +++ b/packages/jsii-calc/test/assembly.jsii @@ -4283,6 +4283,142 @@ ], "name": "DoubleTrouble" }, + "jsii-calc.DynamicPropertyBearer": { + "assembly": "jsii-calc", + "docs": { + "stability": "experimental", + "summary": "Ensures we can override a dynamic property that was inherited." + }, + "fqn": "jsii-calc.DynamicPropertyBearer", + "initializer": { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2794 + }, + "parameters": [ + { + "name": "valueStore", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2793 + }, + "name": "DynamicPropertyBearer", + "properties": [ + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2796 + }, + "name": "dynamicProperty", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2794 + }, + "name": "valueStore", + "type": { + "primitive": "string" + } + } + ] + }, + "jsii-calc.DynamicPropertyBearerChild": { + "assembly": "jsii-calc", + "base": "jsii-calc.DynamicPropertyBearer", + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.DynamicPropertyBearerChild", + "initializer": { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2805 + }, + "parameters": [ + { + "name": "originalValue", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2804 + }, + "methods": [ + { + "docs": { + "returns": "the old value that was set.", + "stability": "experimental", + "summary": "Sets `this.dynamicProperty` to the new value, and returns the old value." + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2816 + }, + "name": "overrideValue", + "parameters": [ + { + "docs": { + "summary": "the new value to be set." + }, + "name": "newValue", + "type": { + "primitive": "string" + } + } + ], + "returns": { + "type": { + "primitive": "string" + } + } + } + ], + "name": "DynamicPropertyBearerChild", + "properties": [ + { + "docs": { + "stability": "experimental" + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2805 + }, + "name": "originalValue", + "type": { + "primitive": "string" + } + } + ] + }, "jsii-calc.EnumDispenser": { "assembly": "jsii-calc", "docs": { @@ -13826,5 +13962,5 @@ } }, "version": "0.0.0", - "fingerprint": "2+VsCif006Pa9j/t5xrvI5psaT2mh2x58UwU31ByN5E=" + "fingerprint": "cyoh4941c6DZUpcqFIkyprTV/kYc5HyNK4JT1ibPKIE=" } diff --git a/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap b/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap index 72fe7d3985..3c95134c36 100644 --- a/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap +++ b/packages/jsii-pacmak/test/__snapshots__/jsii-pacmak.test.ts.snap @@ -7046,6 +7046,8 @@ exports[`Generated code for "jsii-calc": / 1`] = ` ┃ ┃ ┣━ 📄 DoNotRecognizeAnyAsOptional.cs ┃ ┃ ┣━ 📄 DontComplainAboutVariadicAfterOptional.cs ┃ ┃ ┣━ 📄 DoubleTrouble.cs + ┃ ┃ ┣━ 📄 DynamicPropertyBearer.cs + ┃ ┃ ┣━ 📄 DynamicPropertyBearerChild.cs ┃ ┃ ┣━ 📄 EnumDispenser.cs ┃ ┃ ┣━ 📄 EraseUndefinedHashValues.cs ┃ ┃ ┣━ 📄 EraseUndefinedHashValuesOptions.cs @@ -7415,6 +7417,8 @@ exports[`Generated code for "jsii-calc": / 1`] = ` ┃ ┃ ┣━ 📄 DoNotRecognizeAnyAsOptional.java ┃ ┃ ┣━ 📄 DontComplainAboutVariadicAfterOptional.java ┃ ┃ ┣━ 📄 DoubleTrouble.java + ┃ ┃ ┣━ 📄 DynamicPropertyBearer.java + ┃ ┃ ┣━ 📄 DynamicPropertyBearerChild.java ┃ ┃ ┣━ 📄 EnumDispenser.java ┃ ┃ ┣━ 📄 EraseUndefinedHashValues.java ┃ ┃ ┣━ 📄 EraseUndefinedHashValuesOptions.java @@ -11918,6 +11922,142 @@ exports[`Generated code for "jsii-calc": /dotnet/Amazon.JSII.Tests.Calcu ], "name": "DoubleTrouble" }, + "jsii-calc.DynamicPropertyBearer": { + "assembly": "jsii-calc", + "docs": { + "stability": "experimental", + "summary": "Ensures we can override a dynamic property that was inherited." + }, + "fqn": "jsii-calc.DynamicPropertyBearer", + "initializer": { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2794 + }, + "parameters": [ + { + "name": "valueStore", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2793 + }, + "name": "DynamicPropertyBearer", + "properties": [ + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2796 + }, + "name": "dynamicProperty", + "type": { + "primitive": "string" + } + }, + { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2794 + }, + "name": "valueStore", + "type": { + "primitive": "string" + } + } + ] + }, + "jsii-calc.DynamicPropertyBearerChild": { + "assembly": "jsii-calc", + "base": "jsii-calc.DynamicPropertyBearer", + "docs": { + "stability": "experimental" + }, + "fqn": "jsii-calc.DynamicPropertyBearerChild", + "initializer": { + "docs": { + "stability": "experimental" + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2805 + }, + "parameters": [ + { + "name": "originalValue", + "type": { + "primitive": "string" + } + } + ] + }, + "kind": "class", + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2804 + }, + "methods": [ + { + "docs": { + "returns": "the old value that was set.", + "stability": "experimental", + "summary": "Sets \`this.dynamicProperty\` to the new value, and returns the old value." + }, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2816 + }, + "name": "overrideValue", + "parameters": [ + { + "docs": { + "summary": "the new value to be set." + }, + "name": "newValue", + "type": { + "primitive": "string" + } + } + ], + "returns": { + "type": { + "primitive": "string" + } + } + } + ], + "name": "DynamicPropertyBearerChild", + "properties": [ + { + "docs": { + "stability": "experimental" + }, + "immutable": true, + "locationInModule": { + "filename": "lib/compliance.ts", + "line": 2805 + }, + "name": "originalValue", + "type": { + "primitive": "string" + } + } + ] + }, "jsii-calc.EnumDispenser": { "assembly": "jsii-calc", "docs": { @@ -21461,7 +21601,7 @@ exports[`Generated code for "jsii-calc": /dotnet/Amazon.JSII.Tests.Calcu } }, "version": "0.0.0", - "fingerprint": "2+VsCif006Pa9j/t5xrvI5psaT2mh2x58UwU31ByN5E=" + "fingerprint": "cyoh4941c6DZUpcqFIkyprTV/kYc5HyNK4JT1ibPKIE=" } `; @@ -25692,6 +25832,124 @@ namespace Amazon.JSII.Tests.CalculatorNamespace `; +exports[`Generated code for "jsii-calc": /dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DynamicPropertyBearer.cs 1`] = ` +using Amazon.JSII.Runtime.Deputy; + +#pragma warning disable CS0672,CS0809,CS1591 + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// Ensures we can override a dynamic property that was inherited. + /// + /// Stability: Experimental + /// + [JsiiClass(nativeType: typeof(Amazon.JSII.Tests.CalculatorNamespace.DynamicPropertyBearer), fullyQualifiedName: "jsii-calc.DynamicPropertyBearer", parametersJson: "[{\\"name\\":\\"valueStore\\",\\"type\\":{\\"primitive\\":\\"string\\"}}]")] + public class DynamicPropertyBearer : DeputyBase + { + /// + /// Stability: Experimental + /// + public DynamicPropertyBearer(string valueStore): base(new DeputyProps(new object[]{valueStore})) + { + } + + /// Used by jsii to construct an instance of this class from a Javascript-owned object reference + /// The Javascript-owned object reference + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected DynamicPropertyBearer(ByRefValue reference): base(reference) + { + } + + /// Used by jsii to construct an instance of this class from DeputyProps + /// The deputy props + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected DynamicPropertyBearer(DeputyProps props): base(props) + { + } + + /// + /// Stability: Experimental + /// + [JsiiProperty(name: "dynamicProperty", typeJson: "{\\"primitive\\":\\"string\\"}")] + public virtual string DynamicProperty + { + get => GetInstanceProperty(); + set => SetInstanceProperty(value); + } + + /// + /// Stability: Experimental + /// + [JsiiProperty(name: "valueStore", typeJson: "{\\"primitive\\":\\"string\\"}")] + public virtual string ValueStore + { + get => GetInstanceProperty(); + set => SetInstanceProperty(value); + } + } +} + +`; + +exports[`Generated code for "jsii-calc": /dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/DynamicPropertyBearerChild.cs 1`] = ` +using Amazon.JSII.Runtime.Deputy; + +#pragma warning disable CS0672,CS0809,CS1591 + +namespace Amazon.JSII.Tests.CalculatorNamespace +{ + /// + /// Stability: Experimental + /// + [JsiiClass(nativeType: typeof(Amazon.JSII.Tests.CalculatorNamespace.DynamicPropertyBearerChild), fullyQualifiedName: "jsii-calc.DynamicPropertyBearerChild", parametersJson: "[{\\"name\\":\\"originalValue\\",\\"type\\":{\\"primitive\\":\\"string\\"}}]")] + public class DynamicPropertyBearerChild : Amazon.JSII.Tests.CalculatorNamespace.DynamicPropertyBearer + { + /// + /// Stability: Experimental + /// + public DynamicPropertyBearerChild(string originalValue): base(new DeputyProps(new object[]{originalValue})) + { + } + + /// Used by jsii to construct an instance of this class from a Javascript-owned object reference + /// The Javascript-owned object reference + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected DynamicPropertyBearerChild(ByRefValue reference): base(reference) + { + } + + /// Used by jsii to construct an instance of this class from DeputyProps + /// The deputy props + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] + protected DynamicPropertyBearerChild(DeputyProps props): base(props) + { + } + + /// Sets \`this.dynamicProperty\` to the new value, and returns the old value. + /// the new value to be set. + /// the old value that was set. + /// + /// Stability: Experimental + /// + [JsiiMethod(name: "overrideValue", returnsJson: "{\\"type\\":{\\"primitive\\":\\"string\\"}}", parametersJson: "[{\\"docs\\":{\\"summary\\":\\"the new value to be set.\\"},\\"name\\":\\"newValue\\",\\"type\\":{\\"primitive\\":\\"string\\"}}]")] + public virtual string OverrideValue(string newValue) + { + return InvokeInstanceMethod(new System.Type[]{typeof(string)}, new object[]{newValue}); + } + + /// + /// Stability: Experimental + /// + [JsiiProperty(name: "originalValue", typeJson: "{\\"primitive\\":\\"string\\"}")] + public virtual string OriginalValue + { + get => GetInstanceProperty(); + } + } +} + +`; + exports[`Generated code for "jsii-calc": /dotnet/Amazon.JSII.Tests.CalculatorPackageId/Amazon/JSII/Tests/CalculatorNamespace/EnumDispenser.cs 1`] = ` using Amazon.JSII.Runtime.Deputy; @@ -39949,6 +40207,55 @@ func (d *DoubleTrouble) Next() float64 { return 0.0 } +type DynamicPropertyBearerIface interface { + GetDynamicProperty() string + SetDynamicProperty() + GetValueStore() string + SetValueStore() +} + +type DynamicPropertyBearer struct { + DynamicProperty string + ValueStore string +} + + +func (d DynamicPropertyBearer) GetDynamicProperty() string { + return d.DynamicProperty +} + +func (d DynamicPropertyBearer) GetValueStore() string { + return d.ValueStore +} + + +type DynamicPropertyBearerChildIface interface { + GetOriginalValue() string + SetOriginalValue() + OverrideValue() string +} + +type DynamicPropertyBearerChild struct { + OriginalValue string +} + + +func (d DynamicPropertyBearerChild) GetOriginalValue() string { + return d.OriginalValue +} + + +func (d *DynamicPropertyBearerChild) OverrideValue() string { + jsii.NoOpRequest(jsii.NoOpApiRequest { + + Class: "DynamicPropertyBearerChild", + Method: "OverrideValue", + Args: []string{"string",}, + + }) + return "NOOP_RETURN_STRING" +} + type EnumDispenserIface interface { RandomIntegerLikeEnum() AllTypesEnum RandomStringLikeEnum() StringEnum @@ -49633,6 +49940,127 @@ public class DoubleTrouble extends software.amazon.jsii.JsiiObject implements so `; +exports[`Generated code for "jsii-calc": /java/src/main/java/software/amazon/jsii/tests/calculator/DynamicPropertyBearer.java 1`] = ` +package software.amazon.jsii.tests.calculator; + +/** + * Ensures we can override a dynamic property that was inherited. + *

+ * EXPERIMENTAL + */ +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.DynamicPropertyBearer") +public class DynamicPropertyBearer extends software.amazon.jsii.JsiiObject { + + protected DynamicPropertyBearer(final software.amazon.jsii.JsiiObjectRef objRef) { + super(objRef); + } + + protected DynamicPropertyBearer(final software.amazon.jsii.JsiiObject.InitializationMode initializationMode) { + super(initializationMode); + } + + /** + * EXPERIMENTAL + *

+ * @param valueStore This parameter is required. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public DynamicPropertyBearer(final @org.jetbrains.annotations.NotNull java.lang.String valueStore) { + super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, new Object[] { java.util.Objects.requireNonNull(valueStore, "valueStore is required") }); + } + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public @org.jetbrains.annotations.NotNull java.lang.String getDynamicProperty() { + return this.jsiiGet("dynamicProperty", java.lang.String.class); + } + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public void setDynamicProperty(final @org.jetbrains.annotations.NotNull java.lang.String value) { + this.jsiiSet("dynamicProperty", java.util.Objects.requireNonNull(value, "dynamicProperty is required")); + } + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public @org.jetbrains.annotations.NotNull java.lang.String getValueStore() { + return this.jsiiGet("valueStore", java.lang.String.class); + } + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public void setValueStore(final @org.jetbrains.annotations.NotNull java.lang.String value) { + this.jsiiSet("valueStore", java.util.Objects.requireNonNull(value, "valueStore is required")); + } +} + +`; + +exports[`Generated code for "jsii-calc": /java/src/main/java/software/amazon/jsii/tests/calculator/DynamicPropertyBearerChild.java 1`] = ` +package software.amazon.jsii.tests.calculator; + +/** + * EXPERIMENTAL + */ +@javax.annotation.Generated(value = "jsii-pacmak") +@software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) +@software.amazon.jsii.Jsii(module = software.amazon.jsii.tests.calculator.$Module.class, fqn = "jsii-calc.DynamicPropertyBearerChild") +public class DynamicPropertyBearerChild extends software.amazon.jsii.tests.calculator.DynamicPropertyBearer { + + protected DynamicPropertyBearerChild(final software.amazon.jsii.JsiiObjectRef objRef) { + super(objRef); + } + + protected DynamicPropertyBearerChild(final software.amazon.jsii.JsiiObject.InitializationMode initializationMode) { + super(initializationMode); + } + + /** + * EXPERIMENTAL + *

+ * @param originalValue This parameter is required. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public DynamicPropertyBearerChild(final @org.jetbrains.annotations.NotNull java.lang.String originalValue) { + super(software.amazon.jsii.JsiiObject.InitializationMode.JSII); + software.amazon.jsii.JsiiEngine.getInstance().createNewObject(this, new Object[] { java.util.Objects.requireNonNull(originalValue, "originalValue is required") }); + } + + /** + * Sets \`this.dynamicProperty\` to the new value, and returns the old value. + *

+ * EXPERIMENTAL + *

+ * @return the old value that was set. + * @param newValue the new value to be set. This parameter is required. + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public @org.jetbrains.annotations.NotNull java.lang.String overrideValue(final @org.jetbrains.annotations.NotNull java.lang.String newValue) { + return this.jsiiCall("overrideValue", java.lang.String.class, new Object[] { java.util.Objects.requireNonNull(newValue, "newValue is required") }); + } + + /** + * EXPERIMENTAL + */ + @software.amazon.jsii.Stability(software.amazon.jsii.Stability.Level.Experimental) + public @org.jetbrains.annotations.NotNull java.lang.String getOriginalValue() { + return this.jsiiGet("originalValue", java.lang.String.class); + } +} + +`; + exports[`Generated code for "jsii-calc": /java/src/main/java/software/amazon/jsii/tests/calculator/EnumDispenser.java 1`] = ` package software.amazon.jsii.tests.calculator; @@ -62559,6 +62987,8 @@ jsii-calc.DoNotRecognizeAnyAsOptional=software.amazon.jsii.tests.calculator.DoNo jsii-calc.DocumentedClass=software.amazon.jsii.tests.calculator.DocumentedClass jsii-calc.DontComplainAboutVariadicAfterOptional=software.amazon.jsii.tests.calculator.DontComplainAboutVariadicAfterOptional jsii-calc.DoubleTrouble=software.amazon.jsii.tests.calculator.DoubleTrouble +jsii-calc.DynamicPropertyBearer=software.amazon.jsii.tests.calculator.DynamicPropertyBearer +jsii-calc.DynamicPropertyBearerChild=software.amazon.jsii.tests.calculator.DynamicPropertyBearerChild jsii-calc.EnumDispenser=software.amazon.jsii.tests.calculator.EnumDispenser jsii-calc.EraseUndefinedHashValues=software.amazon.jsii.tests.calculator.EraseUndefinedHashValues jsii-calc.EraseUndefinedHashValuesOptions=software.amazon.jsii.tests.calculator.EraseUndefinedHashValuesOptions @@ -65476,6 +65906,95 @@ class DontComplainAboutVariadicAfterOptional( return jsii.invoke(self, "optionalAndVariadic", [optional, *things]) +class DynamicPropertyBearer( + metaclass=jsii.JSIIMeta, + jsii_type="jsii-calc.DynamicPropertyBearer", +): + """Ensures we can override a dynamic property that was inherited. + + stability + :stability: experimental + """ + + def __init__(self, value_store: builtins.str) -> None: + """ + :param value_store: - + + stability + :stability: experimental + """ + jsii.create(DynamicPropertyBearer, self, [value_store]) + + @builtins.property # type: ignore + @jsii.member(jsii_name="dynamicProperty") + def dynamic_property(self) -> builtins.str: + """ + stability + :stability: experimental + """ + return jsii.get(self, "dynamicProperty") + + @dynamic_property.setter # type: ignore + def dynamic_property(self, value: builtins.str) -> None: + jsii.set(self, "dynamicProperty", value) + + @builtins.property # type: ignore + @jsii.member(jsii_name="valueStore") + def value_store(self) -> builtins.str: + """ + stability + :stability: experimental + """ + return jsii.get(self, "valueStore") + + @value_store.setter # type: ignore + def value_store(self, value: builtins.str) -> None: + jsii.set(self, "valueStore", value) + + +class DynamicPropertyBearerChild( + DynamicPropertyBearer, + metaclass=jsii.JSIIMeta, + jsii_type="jsii-calc.DynamicPropertyBearerChild", +): + """ + stability + :stability: experimental + """ + + def __init__(self, original_value: builtins.str) -> None: + """ + :param original_value: - + + stability + :stability: experimental + """ + jsii.create(DynamicPropertyBearerChild, self, [original_value]) + + @jsii.member(jsii_name="overrideValue") + def override_value(self, new_value: builtins.str) -> builtins.str: + """Sets \`\`this.dynamicProperty\`\` to the new value, and returns the old value. + + :param new_value: the new value to be set. + + return + :return: the old value that was set. + + stability + :stability: experimental + """ + return jsii.invoke(self, "overrideValue", [new_value]) + + @builtins.property # type: ignore + @jsii.member(jsii_name="originalValue") + def original_value(self) -> builtins.str: + """ + stability + :stability: experimental + """ + return jsii.get(self, "originalValue") + + class EnumDispenser(metaclass=jsii.JSIIMeta, jsii_type="jsii-calc.EnumDispenser"): """ stability @@ -73136,6 +73655,8 @@ __all__ = [ "DocumentedClass", "DontComplainAboutVariadicAfterOptional", "DoubleTrouble", + "DynamicPropertyBearer", + "DynamicPropertyBearerChild", "EnumDispenser", "EraseUndefinedHashValues", "EraseUndefinedHashValuesOptions", diff --git a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap index a91c49b445..a06859e170 100644 --- a/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/jsii-tree.test.js.snap @@ -811,6 +811,31 @@ exports[`jsii-tree --all 1`] = ` │ │ │ └── returns: string │ │ └─┬ next() method (experimental) │ │ └── returns: number + │ ├─┬ class DynamicPropertyBearer (experimental) + │ │ └─┬ members + │ │ ├─┬ (valueStore) initializer (experimental) + │ │ │ └─┬ parameters + │ │ │ └─┬ valueStore + │ │ │ └── type: string + │ │ ├─┬ dynamicProperty property (experimental) + │ │ │ └── type: string + │ │ └─┬ valueStore property (experimental) + │ │ └── type: string + │ ├─┬ class DynamicPropertyBearerChild (experimental) + │ │ ├── base: DynamicPropertyBearer + │ │ └─┬ members + │ │ ├─┬ (originalValue) initializer (experimental) + │ │ │ └─┬ parameters + │ │ │ └─┬ originalValue + │ │ │ └── type: string + │ │ ├─┬ overrideValue(newValue) method (experimental) + │ │ │ ├─┬ parameters + │ │ │ │ └─┬ newValue + │ │ │ │ └── type: string + │ │ │ └── returns: string + │ │ └─┬ originalValue property (experimental) + │ │ ├── immutable + │ │ └── type: string │ ├─┬ class EnumDispenser (experimental) │ │ └─┬ members │ │ ├─┬ static randomIntegerLikeEnum() method (experimental) @@ -2796,6 +2821,9 @@ exports[`jsii-tree --inheritance 1`] = ` │ ├── class DontComplainAboutVariadicAfterOptional │ ├─┬ class DoubleTrouble │ │ └── interfaces: IFriendlyRandomGenerator + │ ├── class DynamicPropertyBearer + │ ├─┬ class DynamicPropertyBearerChild + │ │ └── base: DynamicPropertyBearer │ ├── class EnumDispenser │ ├── class EraseUndefinedHashValues │ ├── class ExperimentalClass @@ -3398,6 +3426,16 @@ exports[`jsii-tree --members 1`] = ` │ │ ├── () initializer │ │ ├── hello() method │ │ └── next() method + │ ├─┬ class DynamicPropertyBearer + │ │ └─┬ members + │ │ ├── (valueStore) initializer + │ │ ├── dynamicProperty property + │ │ └── valueStore property + │ ├─┬ class DynamicPropertyBearerChild + │ │ └─┬ members + │ │ ├── (originalValue) initializer + │ │ ├── overrideValue(newValue) method + │ │ └── originalValue property │ ├─┬ class EnumDispenser │ │ └─┬ members │ │ ├── static randomIntegerLikeEnum() method @@ -4356,6 +4394,8 @@ exports[`jsii-tree --types 1`] = ` │ ├── class DocumentedClass │ ├── class DontComplainAboutVariadicAfterOptional │ ├── class DoubleTrouble + │ ├── class DynamicPropertyBearer + │ ├── class DynamicPropertyBearerChild │ ├── class EnumDispenser │ ├── class EraseUndefinedHashValues │ ├── class ExperimentalClass diff --git a/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap b/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap index f2f0100149..0106eb7ce9 100644 --- a/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap +++ b/packages/jsii-reflect/test/__snapshots__/type-system.test.js.snap @@ -61,6 +61,8 @@ Array [ "jsii-calc.DocumentedClass", "jsii-calc.DontComplainAboutVariadicAfterOptional", "jsii-calc.DoubleTrouble", + "jsii-calc.DynamicPropertyBearer", + "jsii-calc.DynamicPropertyBearerChild", "jsii-calc.EnumDispenser", "jsii-calc.EraseUndefinedHashValues", "jsii-calc.ExperimentalClass",