diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5353e2ded5..f76c4398e3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Fixed a bug where raw collections requests would not be supported #467
+- Fixes a bug where in memory backing store would not return changed properties to null #243
+- Fixes a bug where generated models would be tied to a specific backing store implementation #400
## [0.0.7] - 2021-08-04
diff --git a/README.md b/README.md
index dac92de4c5..c00e53ed4a 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Kiota accepts the following parameters during the generation:
| Name | Shorthand | Required | Description | Accepted values | Default Value |
| ---- | --------- | -------- | ----------- | --------------- | ------------- |
-| backing-store | b | no | The fully qualified name for the backing store class to use. | A fully qualified class name like `Microsoft.Kiota.Abstractions.Store.InMemoryBackingStore` (CSharp), `com.microsoft.kiota.store.InMemoryBackingStore` (Java), `@microsoft/kiota-abstractions.InMemoryBackingStore` (TypeScript) | Empty string |
+| backing-store | b | no | Enables backing store for models. | Flag. N/A. | false |
| class-name | c | no | The class name to use the for main entry point | A valid class name according to the target language specification. | ApiClient |
| deserializer | ds | no | The fully qualified class names for deserializers. | This parameter can be passed multiple values. A module name like `Microsoft.Kiota.Serialization.Json` that implementats `IParseNodeFactory`. | `Microsoft.Kiota.Serialization.Json.JsonParseNodeFactory` (csharp), `@microsoft/kiota-serialization-json.JsonParseNodeFactory` (typescript), `com.microsoft.kiota.serialization.JsonParseNodeFactory` (java) |
| language | l | no | The programming language to generate the SDK in. | csharp, java, or typescript | csharp |
diff --git a/abstractions/dotnet/src/IHttpCore.cs b/abstractions/dotnet/src/IHttpCore.cs
index 1f6ab4b198..288077b640 100644
--- a/abstractions/dotnet/src/IHttpCore.cs
+++ b/abstractions/dotnet/src/IHttpCore.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions.Serialization;
+using Microsoft.Kiota.Abstractions.Store;
namespace Microsoft.Kiota.Abstractions {
///
@@ -10,7 +11,8 @@ public interface IHttpCore {
///
/// Enables the backing store proxies for the SerializationWriters and ParseNodes in use.
///
- void EnableBackingStore();
+ /// The backing store factory to use.
+ void EnableBackingStore(IBackingStoreFactory backingStoreFactory);
///
/// Gets the serialization writer factory currently in use for the HTTP core service.
///
diff --git a/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj b/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj
index 19efcc8c81..9ff491ce30 100644
--- a/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj
+++ b/abstractions/dotnet/src/Microsoft.Kiota.Abstractions.csproj
@@ -4,7 +4,7 @@
net5.0
true
https://github.com/microsoft/kiota
- 1.0.15
+ 1.0.16
diff --git a/abstractions/dotnet/src/RequestInfo.cs b/abstractions/dotnet/src/RequestInfo.cs
index 0b588e1e37..acc68fc146 100644
--- a/abstractions/dotnet/src/RequestInfo.cs
+++ b/abstractions/dotnet/src/RequestInfo.cs
@@ -41,7 +41,7 @@ public class RequestInfo
///
/// The middleware option to add.
public void AddMiddlewareOptions(params IMiddlewareOption[] options) {
- if(!options?.Any() ?? false) return; // it's a no-op if there are no options and this avoid having to check in the code gen.
+ if(!(options?.Any() ?? false)) return; // it's a no-op if there are no options and this avoid having to check in the code gen.
foreach(var option in options.Where(x => x != null))
if(!_middlewareOptions.TryAdd(option.GetType().FullName, option))
_middlewareOptions[option.GetType().FullName] = option;
diff --git a/abstractions/dotnet/src/serialization/ISerializationWriter.cs b/abstractions/dotnet/src/serialization/ISerializationWriter.cs
index 801b2e3d4b..7b34c1c917 100644
--- a/abstractions/dotnet/src/serialization/ISerializationWriter.cs
+++ b/abstractions/dotnet/src/serialization/ISerializationWriter.cs
@@ -74,6 +74,11 @@ public interface ISerializationWriter : IDisposable {
/// The enum value to be written.
void WriteEnumValue(string key, T? value) where T : struct, Enum;
///
+ /// Writes a null value for the specified key.
+ ///
+ /// The key to be used for the written value. May be null.
+ void WriteNullValue(string key);
+ ///
/// Writes the specified additional data to the stream.
///
/// The additional data to be written.
@@ -91,5 +96,9 @@ public interface ISerializationWriter : IDisposable {
/// Callback called after the serialization process ends.
///
Action OnAfterObjectSerialization { get; set; }
+ ///
+ /// Callback called right after the serialization process starts.
+ ///
+ Action OnStartObjectSerialization { get; set; }
}
}
diff --git a/abstractions/dotnet/src/serialization/SerializationWriterProxyFactory.cs b/abstractions/dotnet/src/serialization/SerializationWriterProxyFactory.cs
index ddf76bba17..6bf67a42f8 100644
--- a/abstractions/dotnet/src/serialization/SerializationWriterProxyFactory.cs
+++ b/abstractions/dotnet/src/serialization/SerializationWriterProxyFactory.cs
@@ -9,22 +9,28 @@ public class SerializationWriterProxyFactory : ISerializationWriterFactory {
private readonly ISerializationWriterFactory _concrete;
private readonly Action _onBefore;
private readonly Action _onAfter;
+ private readonly Action _onStartSerialization;
///
/// Creates a new proxy factory that wraps the specified concrete factory while composing the before and after callbacks.
///
/// The concrete factory to wrap.
- /// The callback to invoke before the serialization of any model object.
- /// The callback to invoke after the serialization of any model object.
+ /// The callback to invoke before the serialization of any model object.
+ /// The callback to invoke after the serialization of any model object.
+ /// The callback to invoke when serialization of the entire model has started.
public SerializationWriterProxyFactory(ISerializationWriterFactory concrete,
- Action onBeforeSerialization, Action onAfterSerialization) {
+ Action onBeforeSerialization,
+ Action onAfterSerialization,
+ Action onStartSerialization) {
_concrete = concrete ?? throw new ArgumentNullException(nameof(concrete));
_onBefore = onBeforeSerialization;
_onAfter = onAfterSerialization;
+ _onStartSerialization = onStartSerialization;
}
public ISerializationWriter GetSerializationWriter(string contentType) {
var writer = _concrete.GetSerializationWriter(contentType);
var originalBefore = writer.OnBeforeObjectSerialization;
var originalAfter = writer.OnAfterObjectSerialization;
+ var originalStart = writer.OnStartObjectSerialization;
writer.OnBeforeObjectSerialization = (x) => {
_onBefore?.Invoke(x); // the callback set by the implementation (e.g. backing store)
originalBefore?.Invoke(x); // some callback that might already be set on the target
@@ -33,6 +39,10 @@ public ISerializationWriter GetSerializationWriter(string contentType) {
_onAfter?.Invoke(x);
originalAfter?.Invoke(x);
};
+ writer.OnStartObjectSerialization = (x, y) => {
+ _onStartSerialization?.Invoke(x, y);
+ originalStart?.Invoke(x, y);
+ };
return writer;
}
}
diff --git a/abstractions/dotnet/src/store/BackingStoreFactorySingleton.cs b/abstractions/dotnet/src/store/BackingStoreFactorySingleton.cs
new file mode 100644
index 0000000000..ae235b6dee
--- /dev/null
+++ b/abstractions/dotnet/src/store/BackingStoreFactorySingleton.cs
@@ -0,0 +1,11 @@
+namespace Microsoft.Kiota.Abstractions.Store {
+ ///
+ /// This class is used to register the backing store factory.
+ ///
+ public class BackingStoreFactorySingleton {
+ ///
+ /// The backing store factory singleton instance.
+ ///
+ public static IBackingStoreFactory Instance { get; set; } = new InMemoryBackingStoreFactory();
+ }
+}
diff --git a/abstractions/dotnet/src/store/BackingStoreSerializationWriterProxyFactory.cs b/abstractions/dotnet/src/store/BackingStoreSerializationWriterProxyFactory.cs
index 25bb8e030b..9dbfd92444 100644
--- a/abstractions/dotnet/src/store/BackingStoreSerializationWriterProxyFactory.cs
+++ b/abstractions/dotnet/src/store/BackingStoreSerializationWriterProxyFactory.cs
@@ -21,6 +21,12 @@ public BackingStoreSerializationWriterProxyFactory(ISerializationWriterFactory c
backedModel.BackingStore.ReturnOnlyChangedValues = false;
backedModel.BackingStore.InitializationCompleted = true;
}
+ },(x, y) => {
+ if(x is IBackedModel backedModel && backedModel.BackingStore != null) {
+ var nullValues = backedModel.BackingStore.EnumerateKeysForValuesChangedToNull();
+ foreach(var key in nullValues)
+ y.WriteNullValue(key);
+ }
}) {}
}
}
diff --git a/abstractions/dotnet/src/store/IBackingStore.cs b/abstractions/dotnet/src/store/IBackingStore.cs
index 734bbb5a5f..00bba32b0c 100644
--- a/abstractions/dotnet/src/store/IBackingStore.cs
+++ b/abstractions/dotnet/src/store/IBackingStore.cs
@@ -21,6 +21,11 @@ public interface IBackingStore {
/// The values available in the backing store.
IEnumerable> Enumerate();
///
+ /// Enumerates the keys for all values that changed to null.
+ ///
+ /// The keys for all values that changed to null.
+ IEnumerable EnumerateKeysForValuesChangedToNull();
+ ///
/// Creates a subscription to any data change happening.
///
/// Callback to be invoked on data changes where the first parameter is the data key, the second the previous value and the third the new value.
diff --git a/abstractions/dotnet/src/store/IBackingStoreFactory.cs b/abstractions/dotnet/src/store/IBackingStoreFactory.cs
new file mode 100644
index 0000000000..80877535ed
--- /dev/null
+++ b/abstractions/dotnet/src/store/IBackingStoreFactory.cs
@@ -0,0 +1,12 @@
+namespace Microsoft.Kiota.Abstractions.Store {
+ ///
+ /// Defines the contract for a factory that creates backing stores.
+ ///
+ public interface IBackingStoreFactory {
+ ///
+ /// Creates a new instance of the backing store.
+ ///
+ /// A new instance of the backing store.
+ IBackingStore CreateBackingStore();
+ }
+}
diff --git a/abstractions/dotnet/src/store/InMemoryBackingStore.cs b/abstractions/dotnet/src/store/InMemoryBackingStore.cs
index 4344cfeb82..466de55083 100644
--- a/abstractions/dotnet/src/store/InMemoryBackingStore.cs
+++ b/abstractions/dotnet/src/store/InMemoryBackingStore.cs
@@ -37,6 +37,9 @@ public IEnumerable> Enumerate() {
return (ReturnOnlyChangedValues ? store.Where(x => !x.Value.Item1) : store)
.Select(x => new KeyValuePair(x.Key, x.Value.Item2));
}
+ public IEnumerable EnumerateKeysForValuesChangedToNull() {
+ return store.Where(x => x.Value.Item1 && x.Value.Item2 == null).Select(x => x.Key);
+ }
public string Subscribe(Action callback) {
var id = Guid.NewGuid().ToString();
Subscribe(callback, id);
diff --git a/abstractions/dotnet/src/store/InMemoryBackingStoreFactory.cs b/abstractions/dotnet/src/store/InMemoryBackingStoreFactory.cs
new file mode 100644
index 0000000000..9845964684
--- /dev/null
+++ b/abstractions/dotnet/src/store/InMemoryBackingStoreFactory.cs
@@ -0,0 +1,10 @@
+namespace Microsoft.Kiota.Abstractions.Store {
+ ///
+ /// This class is used to create instances of .
+ ///
+ public class InMemoryBackingStoreFactory : IBackingStoreFactory {
+ public IBackingStore CreateBackingStore() {
+ return new InMemoryBackingStore();
+ }
+ }
+}
diff --git a/abstractions/java/lib/build.gradle b/abstractions/java/lib/build.gradle
index 35a741340a..dc0e177aa0 100644
--- a/abstractions/java/lib/build.gradle
+++ b/abstractions/java/lib/build.gradle
@@ -46,7 +46,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-abstractions'
- version '1.0.15'
+ version '1.0.16'
from(components.java)
}
}
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/HttpCore.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/HttpCore.java
index 0401f52db6..0ea41d9f31 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/HttpCore.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/HttpCore.java
@@ -8,11 +8,15 @@
import com.microsoft.kiota.serialization.Parsable;
import com.microsoft.kiota.serialization.SerializationWriterFactory;
+import com.microsoft.kiota.store.BackingStoreFactory;
/** Service responsible for translating abstract Request Info into concrete native HTTP requests. */
public interface HttpCore {
- /** Enables the backing store proxies for the SerializationWriters and ParseNodes in use. */
- void enableBackingStore();
+ /**
+ * Enables the backing store proxies for the SerializationWriters and ParseNodes in use.
+ * @param backingStoreFactory The backing store factory to use.
+ */
+ void enableBackingStore(@Nullable final BackingStoreFactory backingStoreFactory);
/**
* Gets the serialization writer factory currently in use for the HTTP core service.
* @return the serialization writer factory currently in use for the HTTP core service.
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriter.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriter.java
index c6b08e821b..f224dc1dee 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriter.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriter.java
@@ -8,6 +8,7 @@
import java.util.EnumSet;
import java.lang.Enum;
import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -92,6 +93,11 @@ public interface SerializationWriter extends Closeable {
* @param value the value to write to the stream.
*/
> void writeEnumValue(@Nullable final String key, @Nullable final T value);
+ /**
+ * Writes a null value for the specified key.
+ * @param key the key to write the value with.
+ */
+ void writeNullValue(@Nullable final String key);
/**
* Writes the specified additional data values to the stream with an optional given key.
* @param value the values to write to the stream.
@@ -109,6 +115,12 @@ public interface SerializationWriter extends Closeable {
*/
@Nullable
Consumer getOnAfterObjectSerialization();
+ /**
+ * Gets the callback called right after the serialization process starts.
+ * @return the callback called right after the serialization process starts.
+ */
+ @Nullable
+ BiConsumer getOnStartObjectSerialization();
/**
* Sets the callback called before the objects gets serialized.
* @param value the callback called before the objects gets serialized.
@@ -119,4 +131,9 @@ public interface SerializationWriter extends Closeable {
* @param value the callback called after the objects gets serialized.
*/
void setOnAfterObjectSerialization(@Nullable final Consumer value);
+ /**
+ * Sets the callback called right after the serialization process starts.
+ * @param value the callback called right after the serialization process starts.
+ */
+ void setOnStartObjectSerialization(@Nullable final BiConsumer value);
}
\ No newline at end of file
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java
index 36fe286315..88dd3cf992 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java
@@ -1,6 +1,7 @@
package com.microsoft.kiota.serialization;
import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import java.util.Objects;
import javax.annotation.Nonnull;
@@ -14,22 +15,28 @@ public String getValidContentType() {
private final SerializationWriterFactory _concrete;
private final Consumer _onBefore;
private final Consumer _onAfter;
+ private final BiConsumer _onStart;
/**
* Creates a new proxy factory that wraps the specified concrete factory while composing the before and after callbacks.
* @param concreteFactory the concrete factory to wrap
- * @param onBefore the callback to invoke before the serialization of any model object.
- * @param onAfter the callback to invoke after the serialization of any model object.
+ * @param onBeforeSerialization the callback to invoke before the serialization of any model object.
+ * @param onAfterSerialization the callback to invoke after the serialization of any model object.
+ * @param onStartSerialization the callback to invoke when the serialization of a model object starts.
*/
public SerializationWriterProxyFactory(@Nonnull final SerializationWriterFactory concrete,
- @Nullable final Consumer onBeforeSerialization, @Nullable final Consumer onAfterSerialization) {
+ @Nullable final Consumer onBeforeSerialization,
+ @Nullable final Consumer onAfterSerialization,
+ @Nullable final BiConsumer onStartObjectSerialization) {
_concrete = Objects.requireNonNull(concrete);
_onBefore = onBeforeSerialization;
_onAfter = onAfterSerialization;
+ _onStart = onStartObjectSerialization;
}
public SerializationWriter getSerializationWriter(final String contentType) {
final SerializationWriter writer = _concrete.getSerializationWriter(contentType);
final Consumer originalBefore = writer.getOnBeforeObjectSerialization();
final Consumer originalAfter = writer.getOnAfterObjectSerialization();
+ final BiConsumer originalStart = writer.getOnStartObjectSerialization();
writer.setOnBeforeObjectSerialization((x) -> {
if(_onBefore != null) {
_onBefore.accept(x); // the callback set by the implementation (e.g. backing store)
@@ -46,6 +53,14 @@ public SerializationWriter getSerializationWriter(final String contentType) {
originalAfter.accept(x);
}
});
+ writer.setOnStartObjectSerialization((x, y) -> {
+ if(_onStart != null) {
+ _onStart.accept(x, y);
+ }
+ if(originalStart != null) {
+ originalStart.accept(x, y);
+ }
+ });
return writer;
}
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStore.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStore.java
index 0c6c716bb1..8dc120944d 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStore.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStore.java
@@ -32,6 +32,12 @@ public interface BackingStore {
@Nonnull
Map enumerate();
/**
+ * Enumerates the keys for all values that changed to null.
+ * @return The keys for the values that changed to null.
+ */
+ @Nonnull
+ Iterable enumerateKeysForValuesChangedToNull();
+ /**
* Creates a subscription to any data change happening.
* @param callback Callback to be invoked on data changes where the first parameter is the data key, the second the previous value and the third the new value.
* @return The subscription Id to use when removing the subscription
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactory.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactory.java
new file mode 100644
index 0000000000..627f1ffd34
--- /dev/null
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactory.java
@@ -0,0 +1,13 @@
+package com.microsoft.kiota.store;
+
+import javax.annotation.Nonnull;
+
+/** Defines the contract for a factory that creates backing stores. */
+public interface BackingStoreFactory {
+ /**
+ * Creates a new instance of the backing store.
+ * @return a new instance of the backing store.
+ */
+ @Nonnull
+ BackingStore createBackingStore();
+}
\ No newline at end of file
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java
new file mode 100644
index 0000000000..5702ec3d75
--- /dev/null
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreFactorySingleton.java
@@ -0,0 +1,7 @@
+package com.microsoft.kiota.store;
+
+/** This class is used to register the backing store factory. */
+public class BackingStoreFactorySingleton {
+ /** The backing store factory singleton instance. */
+ public static BackingStoreFactory instance = new InMemoryBackingStoreFactory();
+}
\ No newline at end of file
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java
index a504e2fd4c..36ef25fda1 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java
@@ -15,16 +15,29 @@ public BackingStoreSerializationWriterProxyFactory(@Nonnull final SerializationW
(x) -> {
if(x instanceof BackedModel) {
final BackedModel backedModel = (BackedModel)x;
- if(backedModel.getBackingStore() != null) {
- backedModel.getBackingStore().setReturnOnlyChangedValues(true);
+ final var backingStore = backedModel.getBackingStore();
+ if(backingStore != null) {
+ backingStore.setReturnOnlyChangedValues(true);
}
}
},(x) -> {
if(x instanceof BackedModel) {
final BackedModel backedModel = (BackedModel)x;
- if(backedModel.getBackingStore() != null) {
- backedModel.getBackingStore().setReturnOnlyChangedValues(false);
- backedModel.getBackingStore().setIsInitializationCompleted(true);
+ final var backingStore = backedModel.getBackingStore();
+ if(backingStore != null) {
+ backingStore.setReturnOnlyChangedValues(false);
+ backingStore.setIsInitializationCompleted(true);
+ }
+ }
+ }, (x, y) -> {
+ if(x instanceof BackedModel) {
+ final BackedModel backedModel = (BackedModel)x;
+ final var backingStore = backedModel.getBackingStore();
+ if(backingStore != null) {
+ final var keys = backingStore.enumerateKeysForValuesChangedToNull();
+ for(final var key : keys) {
+ y.writeNullValue(key);
+ }
}
}
});
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java
index 20d9812c14..6c1e0a0dcf 100644
--- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStore.java
@@ -2,6 +2,8 @@
import java.lang.ClassCastException;
+import java.util.List;
+import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
@@ -48,6 +50,17 @@ public Map enumerate() {
}
return result;
}
+ public Iterable enumerateKeysForValuesChangedToNull() {
+ final List result = new ArrayList<>();
+ for(final Map.Entry> entry : this.store.entrySet()) {
+ final Pair wrapper = entry.getValue();
+ final Object value = wrapper.getValue1();
+ if(value == null && wrapper.getValue0()) {
+ result.add(entry.getKey());
+ }
+ }
+ return result;
+ }
private Object getValueFromWrapper(final Pair wrapper) {
if(wrapper != null) {
final Boolean hasChanged = wrapper.getValue0();
diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java
new file mode 100644
index 0000000000..ccb48ce6c4
--- /dev/null
+++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/store/InMemoryBackingStoreFactory.java
@@ -0,0 +1,9 @@
+package com.microsoft.kiota.store;
+
+/** This class is used to create instances of InMemoryBackingStore */
+public class InMemoryBackingStoreFactory implements BackingStoreFactory {
+ @Override
+ public BackingStore createBackingStore() {
+ return new InMemoryBackingStore();
+ }
+}
diff --git a/abstractions/typescript/package-lock.json b/abstractions/typescript/package-lock.json
index a4425989b7..cb9a04f604 100644
--- a/abstractions/typescript/package-lock.json
+++ b/abstractions/typescript/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-abstractions",
- "version": "1.0.15",
+ "version": "1.0.16",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/abstractions/typescript/package.json b/abstractions/typescript/package.json
index 4bac866b94..a8abc57f07 100644
--- a/abstractions/typescript/package.json
+++ b/abstractions/typescript/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-abstractions",
- "version": "1.0.15",
+ "version": "1.0.16",
"description": "Core abstractions for kiota generated libraries in TypeScript and JavaScript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
diff --git a/abstractions/typescript/src/httpCore.ts b/abstractions/typescript/src/httpCore.ts
index 80094ed1f8..b8e726885a 100644
--- a/abstractions/typescript/src/httpCore.ts
+++ b/abstractions/typescript/src/httpCore.ts
@@ -1,6 +1,7 @@
import { RequestInfo } from "./requestInfo";
import { ResponseHandler } from "./responseHandler";
import { Parsable, SerializationWriterFactory } from "./serialization";
+import { BackingStoreFactory } from "./store";
/** Service responsible for translating abstract Request Info into concrete native HTTP requests. */
export interface HttpCore {
@@ -43,6 +44,9 @@ export interface HttpCore {
* @return a {@link Promise} of void.
*/
sendNoResponseContentAsync(requestInfo: RequestInfo, responseHandler: ResponseHandler | undefined): Promise;
- /** Enables the backing store proxies for the SerializationWriters and ParseNodes in use. */
- enableBackingStore(): void;
+ /**
+ * Enables the backing store proxies for the SerializationWriters and ParseNodes in use.
+ * @param backingStoreFactory the backing store factory to use.
+ */
+ enableBackingStore(backingStoreFactory?: BackingStoreFactory | undefined): void;
}
\ No newline at end of file
diff --git a/abstractions/typescript/src/serialization/serializationWriter.ts b/abstractions/typescript/src/serialization/serializationWriter.ts
index a764466db5..19db279731 100644
--- a/abstractions/typescript/src/serialization/serializationWriter.ts
+++ b/abstractions/typescript/src/serialization/serializationWriter.ts
@@ -57,6 +57,11 @@ export interface SerializationWriter {
* @param values the value to write to the stream.
*/
writeEnumValue(key?: string | undefined, ...values: (T | undefined)[]): void;
+ /**
+ * Writes a null value for the specified key.
+ * @param key the key to write the value with.
+ */
+ writeNullValue(key?: string | undefined) : void;
/**
* Gets the value of the serialized content.
* @return the value of the serialized content.
@@ -77,4 +82,9 @@ export interface SerializationWriter {
* @return the callback called after the object gets serialized.
*/
onAfterObjectSerialization: ((value: Parsable) => void) | undefined;
+ /**
+ * Gets the callback called right after the serialization process starts.
+ * @return the callback called right after the serialization process starts.
+ */
+ onStartObjectSerialization: ((value: Parsable, writer: SerializationWriter) => void) | undefined;
}
\ No newline at end of file
diff --git a/abstractions/typescript/src/serialization/serializationWriterProxyFactory.ts b/abstractions/typescript/src/serialization/serializationWriterProxyFactory.ts
index 3b3f2b417b..5b39613b8f 100644
--- a/abstractions/typescript/src/serialization/serializationWriterProxyFactory.ts
+++ b/abstractions/typescript/src/serialization/serializationWriterProxyFactory.ts
@@ -12,10 +12,12 @@ export abstract class SerializationWriterProxyFactory implements SerializationWr
* @param _concrete the concrete factory to wrap
* @param _onBefore the callback to invoke before the serialization of any model object.
* @param _onAfter the callback to invoke after the serialization of any model object.
+ * @param _onStart the callback to invoke when the serialization of a model object starts
*/
constructor(private readonly _concrete: SerializationWriterFactory,
- private readonly _onBefore: (value: Parsable) => void,
- private readonly _onAfter: (value: Parsable) => void) {
+ private readonly _onBefore?: ((value: Parsable) => void) | undefined,
+ private readonly _onAfter?: ((value: Parsable) => void) | undefined,
+ private readonly _onStart?: ((value: Parsable, writer: SerializationWriter) => void) | undefined) {
if(!_concrete)
throw new Error("_concrete cannot be undefined");
}
@@ -23,6 +25,7 @@ export abstract class SerializationWriterProxyFactory implements SerializationWr
const writer = this._concrete.getSerializationWriter(contentType);
const originalBefore = writer.onBeforeObjectSerialization;
const originalAfter = writer.onAfterObjectSerialization;
+ const originalStart = writer.onStartObjectSerialization;
writer.onBeforeObjectSerialization = (value) => {
this._onBefore && this._onBefore(value);
originalBefore && originalBefore(value);
@@ -31,6 +34,10 @@ export abstract class SerializationWriterProxyFactory implements SerializationWr
this._onAfter && this._onAfter(value);
originalAfter && originalAfter(value);
}
+ writer.onStartObjectSerialization = (value, writer) => {
+ this._onStart && this._onStart(value, writer);
+ originalStart && originalStart(value, writer);
+ }
return writer;
}
diff --git a/abstractions/typescript/src/store/backingStore.ts b/abstractions/typescript/src/store/backingStore.ts
index f32dc80c84..09715b898a 100644
--- a/abstractions/typescript/src/store/backingStore.ts
+++ b/abstractions/typescript/src/store/backingStore.ts
@@ -21,6 +21,11 @@ export interface BackingStore {
*/
enumerate(): {key: string, value: unknown}[];
/**
+ * Enumerates the keys for all values that changed to null.
+ * @return The keys for the values that changed to null.
+ */
+ enumerateKeysForValuesChangedToNull(): string[];
+ /**
* Creates a subscription to any data change happening.
* @param callback Callback to be invoked on data changes where the first parameter is the data key, the second the previous value and the third the new value.
* @param subscriptionId The subscription Id to use.
diff --git a/abstractions/typescript/src/store/backingStoreFactory.ts b/abstractions/typescript/src/store/backingStoreFactory.ts
new file mode 100644
index 0000000000..5803451d85
--- /dev/null
+++ b/abstractions/typescript/src/store/backingStoreFactory.ts
@@ -0,0 +1,10 @@
+import { BackingStore } from "./backingStore";
+
+/** Defines the contract for a factory that creates backing stores. */
+export interface BackingStoreFactory {
+ /**
+ * Creates a new instance of the backing store.
+ * @return a new instance of the backing store.
+ */
+ createBackingStore(): BackingStore;
+}
\ No newline at end of file
diff --git a/abstractions/typescript/src/store/backingStoreFactorySingleton.ts b/abstractions/typescript/src/store/backingStoreFactorySingleton.ts
new file mode 100644
index 0000000000..68829335e8
--- /dev/null
+++ b/abstractions/typescript/src/store/backingStoreFactorySingleton.ts
@@ -0,0 +1,6 @@
+import { BackingStoreFactory } from "./backingStoreFactory";
+import { InMemoryBackingStoreFactory } from "./inMemoryBackingStoreFactory";
+
+export class BackingStoreFactorySingleton {
+ public static instance: BackingStoreFactory = new InMemoryBackingStoreFactory();
+}
\ No newline at end of file
diff --git a/abstractions/typescript/src/store/backingStoreSerializationWriterProxyFactory.ts b/abstractions/typescript/src/store/backingStoreSerializationWriterProxyFactory.ts
index e488bcc435..41d54f7576 100644
--- a/abstractions/typescript/src/store/backingStoreSerializationWriterProxyFactory.ts
+++ b/abstractions/typescript/src/store/backingStoreSerializationWriterProxyFactory.ts
@@ -20,6 +20,14 @@ export class BackingStoreSerializationWriterProxyFactory extends SerializationWr
backedModel.backingStore.returnOnlyChangedValues = false;
backedModel.backingStore.initializationCompleted = true;
}
+ },
+ (value, writer) => {
+ const backedModel = value as unknown as BackedModel;
+ if(backedModel && backedModel.backingStore) {
+ const keys = backedModel.backingStore.enumerateKeysForValuesChangedToNull();
+ for(const key of keys)
+ writer.writeNullValue(key);
+ }
});
}
}
\ No newline at end of file
diff --git a/abstractions/typescript/src/store/inMemoryBackingStore.ts b/abstractions/typescript/src/store/inMemoryBackingStore.ts
index 9a728be265..d179b47b86 100644
--- a/abstractions/typescript/src/store/inMemoryBackingStore.ts
+++ b/abstractions/typescript/src/store/inMemoryBackingStore.ts
@@ -39,6 +39,15 @@ export class InMemoryBackingStore implements BackingStore {
this.store,
(_, k) => { return { key: k, value: this.store.get(k)?.value}});
}
+ public enumerateKeysForValuesChangedToNull(): string[] {
+ const keys: string[] = [];
+ for(const [key, entry] of this.store) {
+ if(entry.changed && !entry.value) {
+ keys.push(key);
+ }
+ }
+ return keys;
+ }
public subscribe(callback: subscriptionCallback, subscriptionId?: string | undefined): string {
if(!callback)
throw new Error("callback cannot be undefined");
diff --git a/abstractions/typescript/src/store/inMemoryBackingStoreFactory.ts b/abstractions/typescript/src/store/inMemoryBackingStoreFactory.ts
new file mode 100644
index 0000000000..9ff53d26be
--- /dev/null
+++ b/abstractions/typescript/src/store/inMemoryBackingStoreFactory.ts
@@ -0,0 +1,10 @@
+import { BackingStore } from "./backingStore";
+import { BackingStoreFactory } from "./backingStoreFactory";
+import { InMemoryBackingStore } from "./inMemoryBackingStore";
+
+/** This class is used to create instances of InMemoryBackingStore */
+export class InMemoryBackingStoreFactory implements BackingStoreFactory {
+ public createBackingStore(): BackingStore {
+ return new InMemoryBackingStore();
+ }
+}
\ No newline at end of file
diff --git a/abstractions/typescript/src/store/index.ts b/abstractions/typescript/src/store/index.ts
index cd14f9cb8c..6d26bb0eda 100644
--- a/abstractions/typescript/src/store/index.ts
+++ b/abstractions/typescript/src/store/index.ts
@@ -1,5 +1,8 @@
export * from './backedModel';
export * from './backingStore';
+export * from './backingStoreFactory';
+export * from './backingStoreFactorySingleton';
export * from './backingStoreParseNodeFactory';
export * from './backingStoreSerializationWriterProxyFactory';
-export * from './inMemoryBackingStore';
\ No newline at end of file
+export * from './inMemoryBackingStore';
+export * from './inMemoryBackingStoreFactory';
\ No newline at end of file
diff --git a/http/dotnet/httpclient/src/HttpCore.cs b/http/dotnet/httpclient/src/HttpCore.cs
index d8b2300579..d61871737b 100644
--- a/http/dotnet/httpclient/src/HttpCore.cs
+++ b/http/dotnet/httpclient/src/HttpCore.cs
@@ -7,6 +7,7 @@
using System.Threading.Tasks;
using Microsoft.Kiota.Abstractions;
using Microsoft.Kiota.Abstractions.Serialization;
+using Microsoft.Kiota.Abstractions.Store;
namespace Microsoft.Kiota.Http.HttpClient
{
@@ -151,12 +152,11 @@ private HttpRequestMessage GetRequestMessageFromRequestInfo(RequestInfo requestI
}
return message;
}
- ///
- /// Enables the backing store for the registered serialization and parse node factories
- ///
- public void EnableBackingStore() {
+ public void EnableBackingStore(IBackingStoreFactory backingStoreFactory) {
pNodeFactory = ApiClientBuilder.EnableBackingStoreForParseNodeFactory(pNodeFactory) ?? throw new InvalidOperationException("Could not enable backing store for the parse node factory");
sWriterFactory = ApiClientBuilder.EnableBackingStoreForSerializationWriterFactory(sWriterFactory) ?? throw new InvalidOperationException("Could not enable backing store for the serializer writer factory");
+ if(backingStoreFactory != null)
+ BackingStoreFactorySingleton.Instance = backingStoreFactory;
}
public void Dispose() {
if(createdClient)
diff --git a/http/dotnet/httpclient/src/Microsoft.Kiota.Http.HttpClient.csproj b/http/dotnet/httpclient/src/Microsoft.Kiota.Http.HttpClient.csproj
index 24e945e100..d13aec45a9 100644
--- a/http/dotnet/httpclient/src/Microsoft.Kiota.Http.HttpClient.csproj
+++ b/http/dotnet/httpclient/src/Microsoft.Kiota.Http.HttpClient.csproj
@@ -4,11 +4,11 @@
net5.0
true
https://github.com/microsoft/kiota
- 1.0.5
+ 1.0.6
-
+
diff --git a/http/java/okhttp/lib/build.gradle b/http/java/okhttp/lib/build.gradle
index 5456401adc..cfbaa03958 100644
--- a/http/java/okhttp/lib/build.gradle
+++ b/http/java/okhttp/lib/build.gradle
@@ -36,7 +36,7 @@ dependencies {
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:30.1.1-jre'
api 'com.squareup.okhttp3:okhttp:4.9.1'
- api 'com.microsoft.kiota:kiota-abstractions:1.0.15'
+ api 'com.microsoft.kiota:kiota-abstractions:1.0.16'
}
publishing {
@@ -53,7 +53,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-http-okhttp'
- version '1.0.5'
+ version '1.0.6'
from(components.java)
}
}
diff --git a/http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/HttpCore.java b/http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/HttpCore.java
index 820c280820..405f036864 100644
--- a/http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/HttpCore.java
+++ b/http/java/okhttp/lib/src/main/java/com/microsoft/kiota/http/HttpCore.java
@@ -24,6 +24,8 @@
import com.microsoft.kiota.serialization.ParseNodeFactory;
import com.microsoft.kiota.serialization.SerializationWriterFactory;
import com.microsoft.kiota.serialization.SerializationWriterFactoryRegistry;
+import com.microsoft.kiota.store.BackingStoreFactory;
+import com.microsoft.kiota.store.BackingStoreFactorySingleton;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
@@ -72,9 +74,12 @@ public HttpCore(@Nonnull final AuthenticationProvider authenticationProvider, @N
public SerializationWriterFactory getSerializationWriterFactory() {
return sWriterFactory;
}
- public void enableBackingStore() {
+ public void enableBackingStore(@Nullable final BackingStoreFactory backingStoreFactory) {
this.pNodeFactory = Objects.requireNonNull(ApiClientBuilder.enableBackingStoreForParseNodeFactory(pNodeFactory));
this.sWriterFactory = Objects.requireNonNull(ApiClientBuilder.enableBackingStoreForSerializationWriterFactory(sWriterFactory));
+ if(backingStoreFactory != null) {
+ BackingStoreFactorySingleton.instance = backingStoreFactory;
+ }
}
@Nonnull
public CompletableFuture> sendCollectionAsync(@Nonnull final RequestInfo requestInfo, @Nonnull final Class targetClass, @Nullable final ResponseHandler responseHandler) {
diff --git a/http/typescript/fetch/package-lock.json b/http/typescript/fetch/package-lock.json
index 2ce53d98b3..e0f6e3a690 100644
--- a/http/typescript/fetch/package-lock.json
+++ b/http/typescript/fetch/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-http-fetch",
- "version": "1.0.5",
+ "version": "1.0.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/http/typescript/fetch/package.json b/http/typescript/fetch/package.json
index 6b8fc1724c..c979296bb2 100644
--- a/http/typescript/fetch/package.json
+++ b/http/typescript/fetch/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-http-fetch",
- "version": "1.0.5",
+ "version": "1.0.6",
"description": "Kiota HttpCore implementation with fetch",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -29,7 +29,7 @@
"registry": "https://npm.pkg.github.com"
},
"dependencies": {
- "@microsoft/kiota-abstractions": "^1.0.15",
+ "@microsoft/kiota-abstractions": "^1.0.16",
"cross-fetch": "^3.1.4",
"web-streams-polyfill": "^3.1.0"
},
diff --git a/http/typescript/fetch/src/httpCore.ts b/http/typescript/fetch/src/httpCore.ts
index 44db699ec4..8108b00ed9 100644
--- a/http/typescript/fetch/src/httpCore.ts
+++ b/http/typescript/fetch/src/httpCore.ts
@@ -1,4 +1,4 @@
-import { AuthenticationProvider, HttpCore as IHttpCore, Parsable, ParseNodeFactory, RequestInfo, ResponseHandler, ParseNodeFactoryRegistry, enableBackingStoreForParseNodeFactory, SerializationWriterFactoryRegistry, enableBackingStoreForSerializationWriterFactory, SerializationWriterFactory } from '@microsoft/kiota-abstractions';
+import { AuthenticationProvider, BackingStoreFactory, BackingStoreFactorySingleton, HttpCore as IHttpCore, Parsable, ParseNodeFactory, RequestInfo, ResponseHandler, ParseNodeFactoryRegistry, enableBackingStoreForParseNodeFactory, SerializationWriterFactoryRegistry, enableBackingStoreForSerializationWriterFactory, SerializationWriterFactory } from '@microsoft/kiota-abstractions';
import { Headers as FetchHeadersCtor } from 'cross-fetch';
import { ReadableStream } from 'web-streams-polyfill';
import { URLSearchParams } from 'url';
@@ -138,11 +138,14 @@ export class HttpCore implements IHttpCore {
return await responseHandler.handleResponseAsync(response);
}
}
- public enableBackingStore = (): void => {
+ public enableBackingStore = (backingStoreFactory?: BackingStoreFactory | undefined): void => {
this.parseNodeFactory = enableBackingStoreForParseNodeFactory(this.parseNodeFactory);
this.serializationWriterFactory = enableBackingStoreForSerializationWriterFactory(this.serializationWriterFactory);
if(!this.serializationWriterFactory || !this.parseNodeFactory)
throw new Error("unable to enable backing store");
+ if(backingStoreFactory) {
+ BackingStoreFactorySingleton.instance = backingStoreFactory;
+ }
}
private addBearerIfNotPresent = async (requestInfo: RequestInfo): Promise => {
if(!requestInfo.URI) {
diff --git a/serialization/dotnet/json/src/JsonSerializationWriter.cs b/serialization/dotnet/json/src/JsonSerializationWriter.cs
index 406b9a29ee..3db1ac5418 100644
--- a/serialization/dotnet/json/src/JsonSerializationWriter.cs
+++ b/serialization/dotnet/json/src/JsonSerializationWriter.cs
@@ -17,6 +17,7 @@ public JsonSerializationWriter()
}
public Action OnBeforeObjectSerialization { get; set; }
public Action OnAfterObjectSerialization { get; set; }
+ public Action OnStartObjectSerialization { get; set; }
public Stream GetSerializedContent() {
writer.Flush();
stream.Position = 0;
@@ -52,6 +53,10 @@ public void WriteDateTimeOffsetValue(string key, DateTimeOffset? value) {
if(!string.IsNullOrEmpty(key) && value.HasValue) writer.WritePropertyName(key);
if(value.HasValue) writer.WriteStringValue(value.Value);
}
+ public void WriteNullValue(string key) {
+ if(!string.IsNullOrEmpty(key)) writer.WritePropertyName(key);
+ writer.WriteNullValue();
+ }
public void WriteEnumValue(string key, T? value) where T : struct, Enum {
if(!string.IsNullOrEmpty(key) && value.HasValue) writer.WritePropertyName(key);
if(value.HasValue) {
@@ -87,6 +92,7 @@ public void WriteObjectValue(string key, T value) where T : IParsable {
if(!string.IsNullOrEmpty(key)) writer.WritePropertyName(key);
OnBeforeObjectSerialization?.Invoke(value);
writer.WriteStartObject();
+ OnStartObjectSerialization?.Invoke(value, this);
value.Serialize(this);
writer.WriteEndObject();
OnAfterObjectSerialization?.Invoke(value);
@@ -142,6 +148,9 @@ private void WriteAnyValue(string key, T value) {
case object o:
WriteNonParsableObjectValue(key, o); // should we support parsables here too?
break;
+ case null:
+ WriteNullValue(key);
+ break;
default:
throw new InvalidOperationException($"error serialization additional data value with key {key}, unknown type {value?.GetType()}");
}
diff --git a/serialization/dotnet/json/src/Microsoft.Kiota.Serialization.Json.csproj b/serialization/dotnet/json/src/Microsoft.Kiota.Serialization.Json.csproj
index 0578b14135..b6f470952f 100644
--- a/serialization/dotnet/json/src/Microsoft.Kiota.Serialization.Json.csproj
+++ b/serialization/dotnet/json/src/Microsoft.Kiota.Serialization.Json.csproj
@@ -4,11 +4,11 @@
net5.0
true
https://github.com/microsoft/kiota
- 1.0.3
+ 1.0.4
-
+
diff --git a/serialization/java/json/lib/build.gradle b/serialization/java/json/lib/build.gradle
index 074a29bf5e..8cd7574bf9 100644
--- a/serialization/java/json/lib/build.gradle
+++ b/serialization/java/json/lib/build.gradle
@@ -36,7 +36,7 @@ dependencies {
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:30.1.1-jre'
api 'com.google.code.gson:gson:2.8.6'
- api 'com.microsoft.kiota:kiota-abstractions:1.0.13'
+ api 'com.microsoft.kiota:kiota-abstractions:1.0.16'
}
publishing {
@@ -53,7 +53,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-serialization-json'
- version '1.0.3'
+ version '1.0.16'
from(components.java)
}
}
diff --git a/serialization/java/json/lib/src/main/java/com/microsoft/kiota/serialization/JsonSerializationWriter.java b/serialization/java/json/lib/src/main/java/com/microsoft/kiota/serialization/JsonSerializationWriter.java
index f8be9f5180..c471727951 100644
--- a/serialization/java/json/lib/src/main/java/com/microsoft/kiota/serialization/JsonSerializationWriter.java
+++ b/serialization/java/json/lib/src/main/java/com/microsoft/kiota/serialization/JsonSerializationWriter.java
@@ -22,6 +22,7 @@
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
+import java.util.function.BiConsumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@@ -153,6 +154,9 @@ public void writeObjectValue(final String key, final T valu
onBeforeObjectSerialization.accept(value);
}
writer.beginObject();
+ if(onStartObjectSerialization != null) {
+ onStartObjectSerialization.accept(value, this);
+ }
value.serialize(this);
writer.endObject();
if(onAfterObjectSerialization != null) {
@@ -176,6 +180,16 @@ public > void writeEnumValue(@Nullable final String key, @Null
this.writeStringValue(key, getStringValueFromValuedEnum(value));
}
}
+ public void writeNullValue(@Nullable final String key) {
+ try {
+ if(key != null && !key.isEmpty()) {
+ writer.name(key);
+ }
+ writer.nullValue();
+ } catch (IOException ex) {
+ throw new RuntimeException("could not serialize value", ex);
+ }
+ }
private > String getStringValueFromValuedEnum(final T value) {
if(value instanceof ValuedEnum) {
final ValuedEnum valued = (ValuedEnum)value;
@@ -242,6 +256,8 @@ else if(value instanceof Iterable>)
this.writeCollectionOfPrimitiveValues(key, (Iterable>)value);
else if(!valueClass.isPrimitive())
this.writeNonParsableObject(key, value);
+ else if(value == null)
+ this.writeNullValue(key);
else
throw new RuntimeException("unknown type to serialize " + valueClass.getName());
}
@@ -255,6 +271,9 @@ public Consumer getOnBeforeObjectSerialization() {
public Consumer getOnAfterObjectSerialization() {
return this.onAfterObjectSerialization;
}
+ public BiConsumer getOnStartObjectSerialization() {
+ return this.onStartObjectSerialization;
+ }
private Consumer onBeforeObjectSerialization;
public void setOnBeforeObjectSerialization(final Consumer value) {
this.onBeforeObjectSerialization = value;
@@ -263,4 +282,8 @@ public void setOnBeforeObjectSerialization(final Consumer value) {
public void setOnAfterObjectSerialization(final Consumer value) {
this.onAfterObjectSerialization = value;
}
+ private BiConsumer onStartObjectSerialization;
+ public void setOnStartObjectSerialization(final BiConsumer value) {
+ this.onStartObjectSerialization = value;
+ }
}
diff --git a/serialization/typescript/json/package-lock.json b/serialization/typescript/json/package-lock.json
index 4b2b95148d..119c84c6c7 100644
--- a/serialization/typescript/json/package-lock.json
+++ b/serialization/typescript/json/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-serialization-json",
- "version": "1.0.3",
+ "version": "1.0.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/serialization/typescript/json/package.json b/serialization/typescript/json/package.json
index 178d1b93c2..60bda8c0c2 100644
--- a/serialization/typescript/json/package.json
+++ b/serialization/typescript/json/package.json
@@ -1,6 +1,6 @@
{
"name": "@microsoft/kiota-serialization-json",
- "version": "1.0.3",
+ "version": "1.0.4",
"description": "Implementation of Kiota Serialization interfaces for JSON",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@@ -34,7 +34,7 @@
"registry": "https://npm.pkg.github.com"
},
"dependencies": {
- "@microsoft/kiota-abstractions": "^1.0.13",
+ "@microsoft/kiota-abstractions": "^1.0.16",
"web-streams-polyfill": "^3.1.0"
}
}
diff --git a/serialization/typescript/json/src/jsonSerializationWriter.ts b/serialization/typescript/json/src/jsonSerializationWriter.ts
index 3fffebfb9d..36a16a24d3 100644
--- a/serialization/typescript/json/src/jsonSerializationWriter.ts
+++ b/serialization/typescript/json/src/jsonSerializationWriter.ts
@@ -7,6 +7,7 @@ export class JsonSerializationWriter implements SerializationWriter {
private static propertySeparator = `,`;
public onBeforeObjectSerialization: ((value: Parsable) => void) | undefined;
public onAfterObjectSerialization: ((value: Parsable) => void) | undefined;
+ public onStartObjectSerialization: ((value: Parsable, writer: SerializationWriter) => void) | undefined;
public writeStringValue = (key?: string, value?: string): void => {
key && value && this.writePropertyName(key);
value && this.writer.push(`"${value}"`);
@@ -35,6 +36,11 @@ export class JsonSerializationWriter implements SerializationWriter {
value && this.writer.push(`"${value.toISOString()}"`);
key && value && this.writer.push(JsonSerializationWriter.propertySeparator);
}
+ public writeNullValue = (key?: string): void => {
+ key && this.writePropertyName(key);
+ this.writer.push(`null`);
+ key && this.writer.push(JsonSerializationWriter.propertySeparator);
+ }
public writeCollectionOfPrimitiveValues = (key?: string, values?: T[]): void => {
if(values) {
key && this.writePropertyName(key);
@@ -67,8 +73,9 @@ export class JsonSerializationWriter implements SerializationWriter {
if(key) {
this.writePropertyName(key);
}
- this.writer.push(`{`);
this.onBeforeObjectSerialization && this.onBeforeObjectSerialization(value);
+ this.writer.push(`{`);
+ this.onStartObjectSerialization && this.onStartObjectSerialization(value, this);
value.serialize(this);
this.onAfterObjectSerialization && this.onAfterObjectSerialization(value);
if(this.writer.length > 0 && this.writer[this.writer.length - 1] === JsonSerializationWriter.propertySeparator) { //removing the last separator
@@ -110,7 +117,9 @@ export class JsonSerializationWriter implements SerializationWriter {
private writeAnyValue = (key?: string | undefined, value?: unknown | undefined) : void => {
if(value) {
const valueType = typeof value;
- if(valueType === "boolean") {
+ if(!value) {
+ this.writeNullValue(key);
+ }else if(valueType === "boolean") {
this.writeBooleanValue(key, value as any as boolean);
} else if (valueType === "string") {
this.writeStringValue(key, value as any as string);
diff --git a/src/Kiota.Builder/CodeDOM/CodeParameter.cs b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
index be3f1480fa..a5bcf9a394 100644
--- a/src/Kiota.Builder/CodeDOM/CodeParameter.cs
+++ b/src/Kiota.Builder/CodeDOM/CodeParameter.cs
@@ -14,7 +14,8 @@ public enum CodeParameterKind
HttpCore,
CurrentPath,
Options,
- Serializer
+ Serializer,
+ BackingStore
}
public class CodeParameter : CodeTerminal, ICloneable, IDocumentedElement
diff --git a/src/Kiota.Builder/GenerationConfiguration.cs b/src/Kiota.Builder/GenerationConfiguration.cs
index 4faefe532d..4f05dd3dbf 100644
--- a/src/Kiota.Builder/GenerationConfiguration.cs
+++ b/src/Kiota.Builder/GenerationConfiguration.cs
@@ -10,11 +10,8 @@ public class GenerationConfiguration {
public string ApiRootUrl { get; set; } = "https://graph.microsoft.com/v1.0";
public List PropertiesPrefixToStrip { get; set; } = new() { "@odata."};
public HashSet IgnoredRequestContentTypes { get; set; } = new();
- public string BackingStore { get; set; } = string.Empty;
+ public bool UsesBackingStore { get; set; }
public List Serializers { get; set; } = new();
- public bool UsesBackingStore {
- get => !string.IsNullOrEmpty(BackingStore);
- }
public List Deserializers { get; set; } = new();
}
}
diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs
index 19f1b1e642..45d1c37ece 100644
--- a/src/Kiota.Builder/KiotaBuilder.cs
+++ b/src/Kiota.Builder/KiotaBuilder.cs
@@ -199,7 +199,7 @@ public void ApplyLanguageRefinement(GenerationConfiguration config, CodeNamespac
public async Task CreateLanguageSourceFilesAsync(GenerationLanguage language, CodeNamespace generatedCode)
{
- var languageWriter = LanguageWriter.GetLanguageWriter(language, this.config.OutputPath, this.config.ClientNamespaceName, this.config.UsesBackingStore);
+ var languageWriter = LanguageWriter.GetLanguageWriter(language, this.config.OutputPath, this.config.ClientNamespaceName);
var stopwatch = new Stopwatch();
stopwatch.Start();
var shouldWriteNamespaceIndices = language == GenerationLanguage.Ruby;
@@ -349,6 +349,35 @@ private void CreatePathManagement(CodeClass currentClass, OpenApiUrlTreeNode cur
Description = httpCoreProperty.Description,
ParameterKind = CodeParameterKind.HttpCore,
});
+ if(isApiClientClass && config.UsesBackingStore) {
+ var backingStoreParam = new CodeParameter(constructor) {
+ Name = "backingStore",
+ Optional = true,
+ Description = "The backing store to use for the models.",
+ ParameterKind = CodeParameterKind.BackingStore,
+ };
+ var factoryInterfaceName = $"{backingStoreInterface}Factory";
+ backingStoreParam.Type = new CodeType(backingStoreParam) {
+ Name = factoryInterfaceName,
+ IsNullable = true,
+ };
+ constructor.AddParameter(backingStoreParam);
+ var backingStoreInterfaceUsing = new CodeUsing(currentClass) {
+ Name = factoryInterfaceName,
+ };
+ backingStoreInterfaceUsing.Declaration = new CodeType(backingStoreInterfaceUsing) {
+ Name = storeNamespaceName,
+ IsExternal = true,
+ };
+ var backingStoreSingletonUsing = new CodeUsing(currentClass) {
+ Name = backingStoreSingleton,
+ };
+ backingStoreSingletonUsing.Declaration = new CodeType(backingStoreSingletonUsing) {
+ Name = storeNamespaceName,
+ IsExternal = true,
+ };
+ currentClass.AddUsing(backingStoreInterfaceUsing, backingStoreSingletonUsing);
+ }
}
private static Func shortestNamespaceOrder = (x) => x.Parent.Name.Split('.').Length;
///
@@ -751,6 +780,7 @@ private void CreatePropertiesForModelClass(OpenApiUrlTreeNode currentNode, OpenA
private const string additionalDataPropName = "AdditionalData";
private const string backingStorePropertyName = "BackingStore";
private const string backingStoreInterface = "IBackingStore";
+ private const string backingStoreSingleton = "BackingStoreFactorySingleton";
private const string backedModelInterface = "IBackedModel";
private const string storeNamespaceName = "Microsoft.Kiota.Abstractions.Store";
private void AddSerializationMembers(CodeClass model, bool includeAdditionalProperties) {
@@ -809,12 +839,10 @@ private void AddSerializationMembers(CodeClass model, bool includeAdditionalProp
if(!model.ContainsMember(backingStorePropertyName) &&
config.UsesBackingStore &&
!(model.GetGreatestGrandparent(model)?.ContainsMember(backingStorePropertyName) ?? false)) {
- var storeImplFragments = config.BackingStore.Split('.');
- var storeImplClassName = storeImplFragments.Last();
var backingStoreProperty = new CodeProperty(model) {
Name = backingStorePropertyName,
Access = AccessModifier.Public,
- DefaultValue = $"new {storeImplClassName}()",
+ DefaultValue = $"BackingStoreFactorySingleton.Instance.CreateBackingStore()",
PropertyKind = CodePropertyKind.BackingStore,
Description = "Stores model information.",
ReadOnly = true,
@@ -841,10 +869,10 @@ private void AddSerializationMembers(CodeClass model, bool includeAdditionalProp
IsExternal = true
};
var storeImplUsing = new CodeUsing(model) {
- Name = storeImplClassName,
+ Name = backingStoreSingleton,
};
storeImplUsing.Declaration = new CodeType(storeImplUsing) {
- Name = storeImplFragments.SkipLast(1).Aggregate((x, y) => $"{x}.{y}"),
+ Name = storeNamespaceName,
IsExternal = true,
};
model.AddUsing(backingStoreUsing, backedModelUsing, storeImplUsing);
diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
index 77652803ef..3712d7ebbc 100644
--- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
+++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs
@@ -61,20 +61,36 @@ private static bool ReplaceSerializationModules(CodeElement generatedCode, Func<
}
internal const string GetterPrefix = "get-";
internal const string SetterPrefix = "set-";
- protected static void CorrectCoreTypesForBackingStoreUsings(CodeElement currentElement, string storeNamespace) {
- if(currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model)
+ protected static void CorrectCoreTypesForBackingStore(CodeElement currentElement, string storeNamespace, string defaultPropertyValue) {
+ if(currentElement is CodeClass currentClass && currentClass.IsOfKind(CodeClassKind.Model, CodeClassKind.RequestBuilder)
&& currentClass.StartBlock is CodeClass.Declaration currentDeclaration) {
- foreach(var backingStoreUsing in currentDeclaration.Usings.Where(x => "Microsoft.Kiota.Abstractions.Store".Equals(x.Declaration.Name, StringComparison.OrdinalIgnoreCase))) {
- if(backingStoreUsing?.Declaration != null) {
- backingStoreUsing.Name = backingStoreUsing.Name[1..]; // removing the "I"
- backingStoreUsing.Declaration.Name = storeNamespace;
- }
- }
+ CorrectCoreTypeForBackingStoreUsings(currentDeclaration, storeNamespace, defaultPropertyValue);
var backedModelImplements = currentDeclaration.Implements.FirstOrDefault(x => "IBackedModel".Equals(x.Name, StringComparison.OrdinalIgnoreCase));
if(backedModelImplements != null)
backedModelImplements.Name = backedModelImplements.Name[1..]; //removing the "I"
+ var backingStoreProperty = currentClass.GetChildElements(true).OfType().FirstOrDefault(x => x.IsOfKind(CodePropertyKind.BackingStore));
+ if(backingStoreProperty != null)
+ backingStoreProperty.DefaultValue = defaultPropertyValue;
+
+ }
+ CrawlTree(currentElement, (x) => CorrectCoreTypesForBackingStore(x, storeNamespace, defaultPropertyValue));
+ }
+ private static void CorrectCoreTypeForBackingStoreUsings(CodeClass.Declaration currentDeclaration, string storeNamespace, string defaultPropertyValue) {
+ foreach(var backingStoreUsing in currentDeclaration.Usings.Where(x => "Microsoft.Kiota.Abstractions.Store".Equals(x.Declaration.Name, StringComparison.OrdinalIgnoreCase))) {
+ if(backingStoreUsing?.Declaration != null) {
+ if(backingStoreUsing.Name.StartsWith("I"))
+ backingStoreUsing.Name = backingStoreUsing.Name[1..]; // removing the "I"
+ backingStoreUsing.Declaration.Name = storeNamespace;
+ }
}
- CrawlTree(currentElement, (x) => CorrectCoreTypesForBackingStoreUsings(x, storeNamespace));
+ var defaultValueUsing = currentDeclaration
+ .Usings
+ .FirstOrDefault(x => "BackingStoreFactorySingleton".Equals(x.Name, StringComparison.OrdinalIgnoreCase) &&
+ x.Declaration != null &&
+ x.Declaration.IsExternal &&
+ x.Declaration.Name.Equals(storeNamespace, StringComparison.OrdinalIgnoreCase));
+ if(defaultValueUsing != null)
+ defaultValueUsing.Name = defaultPropertyValue.Split('.').First();
}
private static bool DoesAnyParentHaveAPropertyWithDefaultValue(CodeClass current) {
if(current.StartBlock is CodeClass.Declaration currentDeclaration &&
diff --git a/src/Kiota.Builder/Refiners/JavaRefiner.cs b/src/Kiota.Builder/Refiners/JavaRefiner.cs
index f5c15164b3..e6db38bbd9 100644
--- a/src/Kiota.Builder/Refiners/JavaRefiner.cs
+++ b/src/Kiota.Builder/Refiners/JavaRefiner.cs
@@ -30,7 +30,7 @@ public override void Refine(CodeNamespace generatedCode)
CodePropertyKind.BackingStore,
}, _configuration.UsesBackingStore, true);
AddConstructorsForDefaultValues(generatedCode, true);
- CorrectCoreTypesForBackingStoreUsings(generatedCode, "com.microsoft.kiota.store");
+ CorrectCoreTypesForBackingStore(generatedCode, "com.microsoft.kiota.store", "BackingStoreFactorySingleton.instance.createBackingStore()");
ReplaceDefaultSerializationModules(generatedCode, "com.microsoft.kiota.serialization.JsonSerializationWriterFactory");
ReplaceDefaultDeserializationModules(generatedCode, "com.microsoft.kiota.serialization.JsonParseNodeFactory");
AddSerializationModulesImport(generatedCode);
@@ -134,7 +134,7 @@ private static void CorrectMethodType(CodeMethod currentMethod) {
currentMethod.Name = "getFieldDeserializers";
}
else if(currentMethod.IsOfKind(CodeMethodKind.ClientConstructor))
- currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore))
+ currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore, CodeParameterKind.BackingStore))
.Where(x => x.Type.Name.StartsWith("I", StringComparison.OrdinalIgnoreCase))
.ToList()
.ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I"
diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
index 7f3f2016b9..e6572452bf 100644
--- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
+++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs
@@ -11,7 +11,7 @@ public override void Refine(CodeNamespace generatedCode)
AddDefaultImports(generatedCode, Array.Empty>(), defaultNamespacesForModels, defaultNamespacesForRequestBuilders, defaultSymbolsForApiClient);
ReplaceIndexersByMethodsWithParameter(generatedCode, generatedCode, "ById");
CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType);
- CorrectCoreTypesForBackingStoreUsings(generatedCode, "@microsoft/kiota-abstractions");
+ CorrectCoreTypesForBackingStore(generatedCode, "@microsoft/kiota-abstractions", "BackingStoreFactorySingleton.instance.createBackingStore()");
FixReferencesToEntityType(generatedCode);
AddPropertiesAndMethodTypesImports(generatedCode, true, true, true);
AddParsableInheritanceForModelClasses(generatedCode);
@@ -79,7 +79,7 @@ private static void CorrectMethodType(CodeMethod currentMethod) {
else if(currentMethod.IsOfKind(CodeMethodKind.Deserializer))
currentMethod.ReturnType.Name = $"Map void>";
else if(currentMethod.IsOfKind(CodeMethodKind.ClientConstructor))
- currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore))
+ currentMethod.Parameters.Where(x => x.IsOfKind(CodeParameterKind.HttpCore, CodeParameterKind.BackingStore))
.Where(x => x.Type.Name.StartsWith("I", StringComparison.InvariantCultureIgnoreCase))
.ToList()
.ForEach(x => x.Type.Name = x.Type.Name[1..]); // removing the "I"
diff --git a/src/Kiota.Builder/Writers/CSharp/CSharpWriter.cs b/src/Kiota.Builder/Writers/CSharp/CSharpWriter.cs
index c04b16a08d..d37bc33762 100644
--- a/src/Kiota.Builder/Writers/CSharp/CSharpWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CSharpWriter.cs
@@ -2,7 +2,7 @@
{
public class CSharpWriter : LanguageWriter
{
- public CSharpWriter(string rootPath, string clientNamespaceName, bool usesBackingStore)
+ public CSharpWriter(string rootPath, string clientNamespaceName)
{
PathSegmenter = new CSharpPathSegmenter(rootPath, clientNamespaceName);
var conventionService = new CSharpConventionService();
@@ -10,7 +10,7 @@ public CSharpWriter(string rootPath, string clientNamespaceName, bool usesBackin
AddCodeElementWriter(new CodeClassEndWriter(conventionService));
AddCodeElementWriter(new CodeEnumWriter(conventionService));
AddCodeElementWriter(new CodeIndexerWriter(conventionService));
- AddCodeElementWriter(new CodeMethodWriter(conventionService, usesBackingStore));
+ AddCodeElementWriter(new CodeMethodWriter(conventionService));
AddCodeElementWriter(new CodePropertyWriter(conventionService));
AddCodeElementWriter(new CodeTypeWriter(conventionService));
diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
index e201e7b767..67a4112772 100644
--- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs
@@ -6,10 +6,7 @@
namespace Kiota.Builder.Writers.CSharp {
public class CodeMethodWriter : BaseElementWriter
{
- private readonly bool _usesBackingStore;
- public CodeMethodWriter(CSharpConventionService conventionService, bool usesBackingStore): base(conventionService) {
- _usesBackingStore = usesBackingStore;
- }
+ public CodeMethodWriter(CSharpConventionService conventionService): base(conventionService) { }
public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer)
{
if(codeElement == null) throw new ArgumentNullException(nameof(codeElement));
@@ -64,15 +61,16 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
writer.DecreaseIndent();
writer.WriteLine("}");
}
- private void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
+ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
var httpCoreProperty = parentClass.GetChildElements(true).OfType().FirstOrDefault(x => x.IsOfKind(CodePropertyKind.HttpCore));
var httpCoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.HttpCore));
+ var backingStoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.BackingStore));
var httpCorePropertyName = httpCoreProperty.Name.ToFirstCharacterUpperCase();
writer.WriteLine($"{httpCorePropertyName} = {httpCoreParameter.Name};");
WriteSerializationRegistration(method.SerializerModules, writer, "RegisterDefaultSerializer");
WriteSerializationRegistration(method.DeserializerModules, writer, "RegisterDefaultDeserializer");
- if(_usesBackingStore)
- writer.WriteLine($"{httpCorePropertyName}.EnableBackingStore();");
+ if(backingStoreParameter != null)
+ writer.WriteLine($"{httpCorePropertyName}.EnableBackingStore({backingStoreParameter.Name});");
}
private static void WriteSerializationRegistration(List serializationClassNames, LanguageWriter writer, string methodName) {
if(serializationClassNames != null)
diff --git a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
index 8e7e32127e..76cdb30b68 100644
--- a/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/Java/CodeMethodWriter.cs
@@ -7,10 +7,7 @@
namespace Kiota.Builder.Writers.Java {
public class CodeMethodWriter : BaseElementWriter
{
- private readonly bool _usesBackingStore;
- public CodeMethodWriter(JavaConventionService conventionService, bool usesBackingStore) : base(conventionService){
- _usesBackingStore = usesBackingStore;
- }
+ public CodeMethodWriter(JavaConventionService conventionService) : base(conventionService){}
public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer)
{
if(codeElement == null) throw new ArgumentNullException(nameof(codeElement));
@@ -76,15 +73,16 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
writer.DecreaseIndent();
writer.WriteLine("}");
}
- private void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
+ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
var httpCoreProperty = parentClass.GetChildElements(true).OfType().FirstOrDefault(x => x.IsOfKind(CodePropertyKind.HttpCore));
var httpCoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.HttpCore));
+ var backingStoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.BackingStore));
var httpCorePropertyName = httpCoreProperty.Name.ToFirstCharacterLowerCase();
writer.WriteLine($"this.{httpCorePropertyName} = {httpCoreParameter.Name};");
WriteSerializationRegistration(method.SerializerModules, writer, "registerDefaultSerializer");
WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer");
- if(_usesBackingStore)
- writer.WriteLine($"this.{httpCorePropertyName}.enableBackingStore();");
+ if(backingStoreParameter != null)
+ writer.WriteLine($"this.{httpCorePropertyName}.enableBackingStore({backingStoreParameter.Name});");
}
private static void WriteSerializationRegistration(List serializationModules, LanguageWriter writer, string methodName) {
if(serializationModules != null)
diff --git a/src/Kiota.Builder/Writers/Java/JavaWriter.cs b/src/Kiota.Builder/Writers/Java/JavaWriter.cs
index e64d3b8ef7..b34b5d0441 100644
--- a/src/Kiota.Builder/Writers/Java/JavaWriter.cs
+++ b/src/Kiota.Builder/Writers/Java/JavaWriter.cs
@@ -2,14 +2,14 @@ namespace Kiota.Builder.Writers.Java
{
public class JavaWriter : LanguageWriter
{
- public JavaWriter(string rootPath, string clientNamespaceName, bool usesBackingStore)
+ public JavaWriter(string rootPath, string clientNamespaceName)
{
PathSegmenter = new JavaPathSegmenter(rootPath, clientNamespaceName);
var conventionService = new JavaConventionService();
AddCodeElementWriter(new CodeClassDeclarationWriter(conventionService));
AddCodeElementWriter(new CodeClassEndWriter());
AddCodeElementWriter(new CodeEnumWriter(conventionService));
- AddCodeElementWriter(new CodeMethodWriter(conventionService, usesBackingStore));
+ AddCodeElementWriter(new CodeMethodWriter(conventionService));
AddCodeElementWriter(new CodePropertyWriter(conventionService));
AddCodeElementWriter(new CodeTypeWriter(conventionService));
}
diff --git a/src/Kiota.Builder/Writers/LanguageWriter.cs b/src/Kiota.Builder/Writers/LanguageWriter.cs
index c54d922987..b87d20696a 100644
--- a/src/Kiota.Builder/Writers/LanguageWriter.cs
+++ b/src/Kiota.Builder/Writers/LanguageWriter.cs
@@ -110,12 +110,12 @@ protected void AddCodeElementWriter(ICodeElementWriter writer) where T: Co
Writers.Add(typeof(T), writer);
}
private readonly Dictionary Writers = new(); // we have to type as object because dotnet doesn't have type capture i.e eq for `? extends CodeElement`
- public static LanguageWriter GetLanguageWriter(GenerationLanguage language, string outputPath, string clientNamespaceName, bool usesBackingStore = false) {
+ public static LanguageWriter GetLanguageWriter(GenerationLanguage language, string outputPath, string clientNamespaceName) {
return language switch
{
- GenerationLanguage.CSharp => new CSharpWriter(outputPath, clientNamespaceName, usesBackingStore),
- GenerationLanguage.Java => new JavaWriter(outputPath, clientNamespaceName, usesBackingStore),
- GenerationLanguage.TypeScript => new TypeScriptWriter(outputPath, clientNamespaceName, usesBackingStore),
+ GenerationLanguage.CSharp => new CSharpWriter(outputPath, clientNamespaceName),
+ GenerationLanguage.Java => new JavaWriter(outputPath, clientNamespaceName),
+ GenerationLanguage.TypeScript => new TypeScriptWriter(outputPath, clientNamespaceName),
GenerationLanguage.Ruby => new RubyWriter(outputPath, clientNamespaceName),
_ => throw new InvalidEnumArgumentException($"{language} language currently not supported."),
};
diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
index 8b7d427be7..90c797d056 100644
--- a/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/CodeMethodWriter.cs
@@ -7,11 +7,8 @@
namespace Kiota.Builder.Writers.TypeScript {
public class CodeMethodWriter : BaseElementWriter
{
- public CodeMethodWriter(TypeScriptConventionService conventionService, bool usesBackingStore) : base(conventionService){
- _usesBackingStore = usesBackingStore;
- }
+ public CodeMethodWriter(TypeScriptConventionService conventionService) : base(conventionService){}
private TypeScriptConventionService localConventions;
- private readonly bool _usesBackingStore;
public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter writer)
{
if(codeElement == null) throw new ArgumentNullException(nameof(codeElement));
@@ -73,15 +70,16 @@ public override void WriteCodeElement(CodeMethod codeElement, LanguageWriter wri
writer.DecreaseIndent();
writer.WriteLine("};");
}
- private void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
+ private static void WriteApiConstructorBody(CodeClass parentClass, CodeMethod method, LanguageWriter writer) {
var httpCoreProperty = parentClass.GetChildElements(true).OfType().FirstOrDefault(x => x.IsOfKind(CodePropertyKind.HttpCore));
var httpCoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.HttpCore));
+ var backingStoreParameter = method.Parameters.FirstOrDefault(x => x.IsOfKind(CodeParameterKind.BackingStore));
var httpCorePropertyName = httpCoreProperty.Name.ToFirstCharacterLowerCase();
writer.WriteLine($"this.{httpCorePropertyName} = {httpCoreParameter.Name};");
WriteSerializationRegistration(method.SerializerModules, writer, "registerDefaultSerializer");
WriteSerializationRegistration(method.DeserializerModules, writer, "registerDefaultDeserializer");
- if(_usesBackingStore)
- writer.WriteLine($"this.{httpCorePropertyName}.enableBackingStore();");
+ if(backingStoreParameter != null)
+ writer.WriteLine($"this.{httpCorePropertyName}.enableBackingStore({backingStoreParameter.Name});");
}
private static void WriteSerializationRegistration(List serializationModules, LanguageWriter writer, string methodName) {
if(serializationModules != null)
diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
index c922f659c3..6c4a0c68df 100644
--- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
+++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptWriter.cs
@@ -2,14 +2,14 @@ namespace Kiota.Builder.Writers.TypeScript
{
public class TypeScriptWriter : LanguageWriter
{
- public TypeScriptWriter(string rootPath, string clientNamespaceName, bool usesBackingStore)
+ public TypeScriptWriter(string rootPath, string clientNamespaceName)
{
PathSegmenter = new TypeScriptPathSegmenter(rootPath,clientNamespaceName);
var conventionService = new TypeScriptConventionService(null);
AddCodeElementWriter(new CodeClassDeclarationWriter(conventionService));
AddCodeElementWriter(new CodeClassEndWriter());
AddCodeElementWriter(new CodeEnumWriter(conventionService));
- AddCodeElementWriter(new CodeMethodWriter(conventionService, usesBackingStore));
+ AddCodeElementWriter(new CodeMethodWriter(conventionService));
AddCodeElementWriter(new CodePropertyWriter(conventionService));
AddCodeElementWriter(new CodeTypeWriter(conventionService));
}
diff --git a/src/kiota/KiotaHost.cs b/src/kiota/KiotaHost.cs
index d9c6ff54e6..3a898cd82f 100644
--- a/src/kiota/KiotaHost.cs
+++ b/src/kiota/KiotaHost.cs
@@ -36,7 +36,7 @@ public RootCommand GetRootCommand()
var descriptionOption = new Option("--openapi", "The path to the OpenAPI description file used to generate the code files.") {Argument = new Argument(() => "openapi.yml")};
descriptionOption.AddAlias("-d");
- var backingStoreOption = new Option("--backing-store", "The fully qualified name for the backing store class to use.") {Argument = new Argument()};
+ var backingStoreOption = new Option("--backing-store", "Enables backing store for models.") {Argument = new Argument()};
backingStoreOption.AddAlias("-b");
var serializerOption = new Option>("--serializer", "The fully qualified class names for serializers.") { Argument = new Argument>(() => new List {"Microsoft.Kiota.Serialization.Json.JsonSerializationWriterFactory"}) };
@@ -63,13 +63,13 @@ private void AssignIfNotNullOrEmpty(string input, Action serializer, List deserializer);
- private async Task HandleCommandCall(string output, GenerationLanguage? language, string openapi, string backingstore, string classname, LogLevel loglevel, string namespacename, List serializer, List deserializer) {
+ private delegate Task HandleCommandCallDel(string output, GenerationLanguage? language, string openapi, bool backingstore, string classname, LogLevel loglevel, string namespacename, List serializer, List deserializer);
+ private async Task HandleCommandCall(string output, GenerationLanguage? language, string openapi, bool backingstore, string classname, LogLevel loglevel, string namespacename, List serializer, List deserializer) {
AssignIfNotNullOrEmpty(output, (c, s) => c.OutputPath = s);
AssignIfNotNullOrEmpty(openapi, (c, s) => c.OpenAPIFilePath = s);
AssignIfNotNullOrEmpty(classname, (c, s) => c.ClientClassName = s);
AssignIfNotNullOrEmpty(namespacename, (c, s) => c.ClientNamespaceName = s);
- AssignIfNotNullOrEmpty(backingstore, (c, s) => c.BackingStore = s.TrimQuotes()); //npm modules can start with @ which prompts some terminals to read response files and quotes are not automatically trimmed by the framework
+ Configuration.UsesBackingStore = backingstore;
if (language.HasValue)
Configuration.Language = language.Value;
if(serializer?.Any() ?? false)
diff --git a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs
index b8054b3f5e..8825307be2 100644
--- a/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs
+++ b/tests/Kiota.Builder.IntegrationTests/GenerateSample.cs
@@ -7,25 +7,25 @@ namespace Kiota.Builder.integrationtests
{
public class GenerateSample
{
- [InlineData(GenerationLanguage.CSharp, null)]
- [InlineData(GenerationLanguage.Java, null)]
- [InlineData(GenerationLanguage.TypeScript, null)]
- [InlineData(GenerationLanguage.Ruby, null)]
- [InlineData(GenerationLanguage.CSharp, "Microsoft.Kiota.Abstractions.Store.InMemoryBackingStore")]
- [InlineData(GenerationLanguage.Java, "com.microsoft.kiota.store.InMemoryBackingStore")]
- [InlineData(GenerationLanguage.TypeScript, "@microsoft/kiota-abstractions.InMemoryBackingStore")]
+ [InlineData(GenerationLanguage.CSharp, false)]
+ [InlineData(GenerationLanguage.Java, false)]
+ [InlineData(GenerationLanguage.TypeScript, false)]
+ [InlineData(GenerationLanguage.Ruby, false)]
+ [InlineData(GenerationLanguage.CSharp, true)]
+ [InlineData(GenerationLanguage.Java, true)]
+ [InlineData(GenerationLanguage.TypeScript, true)]
[Theory]
- public async Task GeneratesTodo(GenerationLanguage language, string backingStore) {
+ public async Task GeneratesTodo(GenerationLanguage language, bool backingStore) {
var logger = LoggerFactory.Create((builder) => {
}).CreateLogger();
- var backingStoreSuffix = string.IsNullOrEmpty(backingStore) ? string.Empty : "BackingStore";
+ var backingStoreSuffix = backingStore ? string.Empty : "BackingStore";
var configuration = new GenerationConfiguration
{
Language = GenerationLanguage.CSharp,
OpenAPIFilePath = "ToDoApi.yaml",
OutputPath = $".\\Generated\\{language}{backingStoreSuffix}",
- BackingStore = backingStore,
+ UsesBackingStore = backingStore,
};
await new KiotaBuilder(logger, configuration).GenerateSDK();
}
diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CSharpWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CSharpWriterTests.cs
index 8a7feb6922..e8991130c5 100644
--- a/tests/Kiota.Builder.Tests/Writers/CSharp/CSharpWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CSharpWriterTests.cs
@@ -5,11 +5,11 @@ namespace Kiota.Builder.Writers.CSharp.Tests {
public class CSharpWriterTests {
[Fact]
public void Instanciates() {
- var writer = new CSharpWriter("./", "graph", false);
+ var writer = new CSharpWriter("./", "graph");
Assert.NotNull(writer);
Assert.NotNull(writer.PathSegmenter);
- Assert.Throws(() => new CSharpWriter(null, "graph", false));
- Assert.Throws(() => new CSharpWriter("./", null, false));
+ Assert.Throws(() => new CSharpWriter(null, "graph"));
+ Assert.Throws(() => new CSharpWriter("./", null));
}
}
diff --git a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
index a7a2b1d79d..5e1f7ea401 100644
--- a/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/CSharp/CodeMethodWriterTests.cs
@@ -259,7 +259,7 @@ public void WritesMethodSyncDescription() {
}
[Fact]
public void Defensive() {
- var codeMethodWriter = new CodeMethodWriter(new CSharpConventionService(), false);
+ var codeMethodWriter = new CodeMethodWriter(new CSharpConventionService());
Assert.Throws(() => codeMethodWriter.WriteCodeElement(null, writer));
Assert.Throws(() => codeMethodWriter.WriteCodeElement(method, null));
var originalParent = method.Parent;
@@ -381,7 +381,16 @@ public void WritesApiConstructorWithBackingStore() {
ParameterKind = CodeParameterKind.HttpCore,
Type = coreProp.Type,
});
- var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.CSharp, defaultPath, defaultName, true);
+ var backingStoreParam = new CodeParameter(method) {
+ Name = "backingStore",
+ ParameterKind = CodeParameterKind.BackingStore,
+ };
+ backingStoreParam.Type = new CodeType(backingStoreParam) {
+ Name = "IBackingStore",
+ IsExternal = true,
+ };
+ method.AddParameter(backingStoreParam);
+ var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.CSharp, defaultPath, defaultName);
tempWriter.SetTextWriter(tw);
tempWriter.Write(method);
var result = tw.ToString();
diff --git a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
index cf2e59cfc7..8c557fa949 100644
--- a/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Java/CodeMethodWriterTests.cs
@@ -298,7 +298,7 @@ public void WritesMethodSyncDescription() {
}
[Fact]
public void Defensive() {
- var codeMethodWriter = new CodeMethodWriter(new JavaConventionService(), false);
+ var codeMethodWriter = new CodeMethodWriter(new JavaConventionService());
Assert.Throws(() => codeMethodWriter.WriteCodeElement(null, writer));
Assert.Throws(() => codeMethodWriter.WriteCodeElement(method, null));
var originalParent = method.Parent;
@@ -474,7 +474,16 @@ public void WritesApiConstructorWithBackingStore() {
ParameterKind = CodeParameterKind.HttpCore,
Type = coreProp.Type,
});
- var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.Java, defaultPath, defaultName, true);
+ var backingStoreParam = new CodeParameter(method) {
+ Name = "backingStore",
+ ParameterKind = CodeParameterKind.BackingStore,
+ };
+ backingStoreParam.Type = new CodeType(backingStoreParam) {
+ Name = "BackingStore",
+ IsExternal = true,
+ };
+ method.AddParameter(backingStoreParam);
+ var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.Java, defaultPath, defaultName);
tempWriter.SetTextWriter(tw);
tempWriter.Write(method);
var result = tw.ToString();
diff --git a/tests/Kiota.Builder.Tests/Writers/Java/JavaWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Java/JavaWriterTests.cs
index caf7975a82..1ca160bac1 100644
--- a/tests/Kiota.Builder.Tests/Writers/Java/JavaWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Java/JavaWriterTests.cs
@@ -5,11 +5,11 @@ namespace Kiota.Builder.Writers.Java.Tests {
public class JavaWriterTests {
[Fact]
public void Instanciates() {
- var writer = new JavaWriter("./", "graph", false);
+ var writer = new JavaWriter("./", "graph");
Assert.NotNull(writer);
Assert.NotNull(writer.PathSegmenter);
- Assert.Throws(() => new JavaWriter(null, "graph", false));
- Assert.Throws(() => new JavaWriter("./", null, false));
+ Assert.Throws(() => new JavaWriter(null, "graph"));
+ Assert.Throws(() => new JavaWriter("./", null));
}
}
diff --git a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
index 27be7f04e8..51e2e56648 100644
--- a/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/Ruby/CodeMethodWriterTests.cs
@@ -365,7 +365,16 @@ public void WritesApiConstructorWithBackingStore() {
ParameterKind = CodeParameterKind.HttpCore,
Type = coreProp.Type,
});
- var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.Java, defaultPath, defaultName, true);
+ var backingStoreParam = new CodeParameter(method) {
+ Name = "backingStore",
+ ParameterKind = CodeParameterKind.BackingStore,
+ };
+ backingStoreParam.Type = new CodeType(backingStoreParam) {
+ Name = "BackingStore",
+ IsExternal = true,
+ };
+ method.AddParameter(backingStoreParam);
+ var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.Java, defaultPath, defaultName);
tempWriter.SetTextWriter(tw);
tempWriter.Write(method);
var result = tw.ToString();
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
index 9329190d7c..a8a7cbcd20 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeMethodWriterTests.cs
@@ -268,7 +268,7 @@ public void WritesMethodSyncDescription() {
}
[Fact]
public void Defensive() {
- var codeMethodWriter = new CodeMethodWriter(new TypeScriptConventionService(writer), false);
+ var codeMethodWriter = new CodeMethodWriter(new TypeScriptConventionService(writer));
Assert.Throws(() => codeMethodWriter.WriteCodeElement(null, writer));
Assert.Throws(() => codeMethodWriter.WriteCodeElement(method, null));
var originalParent = method.Parent;
@@ -456,7 +456,16 @@ public void WritesApiConstructorWithBackingStore() {
ParameterKind = CodeParameterKind.HttpCore,
Type = coreProp.Type,
});
- var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, defaultPath, defaultName, true);
+ var backingStoreParam = new CodeParameter(method) {
+ Name = "backingStore",
+ ParameterKind = CodeParameterKind.BackingStore,
+ };
+ backingStoreParam.Type = new CodeType(backingStoreParam) {
+ Name = "BackingStore",
+ IsExternal = true,
+ };
+ method.AddParameter(backingStoreParam);
+ var tempWriter = LanguageWriter.GetLanguageWriter(GenerationLanguage.TypeScript, defaultPath, defaultName);
tempWriter.SetTextWriter(tw);
tempWriter.Write(method);
var result = tw.ToString();
diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptWriterTests.cs
index bad45cefd0..ae01f3eb16 100644
--- a/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptWriterTests.cs
+++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/TypeScriptWriterTests.cs
@@ -5,11 +5,11 @@ namespace Kiota.Builder.Writers.TypeScript.Tests {
public class TypeScriptWriterTests {
[Fact]
public void Instanciates() {
- var writer = new TypeScriptWriter("./", "graph", false);
+ var writer = new TypeScriptWriter("./", "graph");
Assert.NotNull(writer);
Assert.NotNull(writer.PathSegmenter);
- Assert.Throws(() => new TypeScriptWriter(null, "graph", false));
- Assert.Throws(() => new TypeScriptWriter("./", null, false));
+ Assert.Throws(() => new TypeScriptWriter(null, "graph"));
+ Assert.Throws(() => new TypeScriptWriter("./", null));
}
}