From 0a633d398a66e5965923e1e3af2782d5167c03b1 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 12:14:12 -0400 Subject: [PATCH 1/6] - adds support for vendor specific types --- .../Extensions/OpenApiOperationExtensions.cs | 23 ++++--- .../Kiota.Builder.Tests/KiotaBuilderTests.cs | 60 +++++++++++++++++++ 2 files changed, 75 insertions(+), 8 deletions(-) diff --git a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs index e0031b126a..09310e7d5f 100644 --- a/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiOperationExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using Microsoft.OpenApi.Models; namespace Kiota.Builder.Extensions { @@ -10,27 +11,33 @@ public static class OpenApiOperationExtensions { "application/json", "text/plain" }; + /// + /// cleans application/vnd.github.mercy-preview+json to application/json + /// + private static readonly Regex vendorSpecificCleanup = new(@"[^/]+\+", RegexOptions.Compiled); public static OpenApiSchema GetResponseSchema(this OpenApiOperation operation) { // Return Schema that represents all the possible success responses! - // For the moment assume 200s and application/json var schemas = operation.Responses.Where(r => successCodes.Contains(r.Key)) - .SelectMany(re => re.Value.Content) - .Where(c => validMimeTypes.Contains(c.Key)) - .Select(co => co.Value.Schema) + .SelectMany(re => re.Value.GetResponseSchemas()) .Where(s => s is not null); return schemas.FirstOrDefault(); } - public static OpenApiSchema GetResponseSchema(this OpenApiResponse response) + public static IEnumerable GetResponseSchemas(this OpenApiResponse response) { - // For the moment assume application/json var schemas = response.Content - .Where(c => validMimeTypes.Contains(c.Key)) + .Where(c => !string.IsNullOrEmpty(c.Key)) + .Select(c => (Key: c.Key.Split(';', StringSplitOptions.RemoveEmptyEntries).FirstOrDefault(), c.Value)) + .Where(c => validMimeTypes.Contains(c.Key) || validMimeTypes.Contains(vendorSpecificCleanup.Replace(c.Key, string.Empty))) .Select(co => co.Value.Schema) .Where(s => s is not null); - return schemas.FirstOrDefault(); + return schemas; + } + public static OpenApiSchema GetResponseSchema(this OpenApiResponse response) + { + return response.GetResponseSchemas().FirstOrDefault(); } } } diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 964834446e..62cff01257 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -1663,6 +1663,66 @@ public void ModelsDoesntUsePathDescriptionWhenAvailable(){ Assert.NotNull(responseClass); Assert.Null(responseClass.Description); } + [InlineData("application/json")] + [InlineData("application/json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8")] + [InlineData("application/vnd.github.mercy-preview+json")] + [InlineData("application/vnd.github.mercy-preview+json;odata.metadata=minimal;odata.streaming=true;IEEE754Compatible=false;charset=utf-8")] + [Theory] + public void AcceptVendorsTypes(string contentType){ + var myObjectSchema = new OpenApiSchema { + Type = "object", + Properties = new Dictionary { + { + "name", new OpenApiSchema { + Type = "string" + } + } + }, + Reference = new OpenApiReference { + Id = "myobject", + Type = ReferenceType.Schema + }, + UnresolvedReference = false + }; + var document = new OpenApiDocument() { + Paths = new OpenApiPaths() { + ["answer"] = new OpenApiPathItem() { + Operations = { + [OperationType.Get] = new OpenApiOperation() { + Responses = new OpenApiResponses + { + ["200"] = new OpenApiResponse { + Content = { + [contentType] = new OpenApiMediaType { + Schema = myObjectSchema + } + } + }, + } + } + } + } + }, + Components = new() { + Schemas = new Dictionary { + { + "myobject", myObjectSchema + } + } + } + }; + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration() { ClientClassName = "TestClient", ClientNamespaceName = "TestSdk", ApiRootUrl = "https://localhost" }); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + var rbNS = codeModel.FindNamespaceByName("TestSdk.Answer"); + Assert.NotNull(rbNS); + var rbClass = rbNS.Classes.FirstOrDefault(x => x.IsOfKind(CodeClassKind.RequestBuilder)); + Assert.NotNull(rbClass); + var executorMethod = rbClass.Methods.FirstOrDefault(x => x.IsOfKind(CodeMethodKind.RequestExecutor) && x.HttpMethod == HttpMethod.Get); + Assert.NotNull(executorMethod); + Assert.Equal("Myobject", executorMethod.ReturnType.Name); + } [Fact] public void ModelsUseDescriptionWhenAvailable(){ var document = new OpenApiDocument() { From 531834768da704d92d22a6ce1e501f3007ee44ed Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 12:57:18 -0400 Subject: [PATCH 2/6] - adds support for vendor specific content types in java --- abstractions/java/lib/build.gradle | 1 + .../ParseNodeFactoryRegistry.java | 16 ++++++--- .../SerializationWriterFactoryRegistry.java | 14 +++++--- .../kiota/ParseNodeFactoryRegistryTest.java | 34 +++++++++++++++++++ ...erializationWriterFactoryRegistryTest.java | 27 +++++++++++++++ 5 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java create mode 100644 abstractions/java/lib/src/test/java/com/microsoft/kiota/SerializationWriterFactoryRegistryTest.java diff --git a/abstractions/java/lib/build.gradle b/abstractions/java/lib/build.gradle index ad7f0cc383..646767e872 100644 --- a/abstractions/java/lib/build.gradle +++ b/abstractions/java/lib/build.gradle @@ -22,6 +22,7 @@ repositories { dependencies { // Use JUnit Jupiter API for testing. testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2' + testImplementation 'org.mockito:mockito-inline:4.4.0' // Use JUnit Jupiter Engine for testing. testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java index 49db1ae1a8..1ee48654f0 100644 --- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java +++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/ParseNodeFactoryRegistry.java @@ -3,6 +3,7 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Objects; +import java.util.regex.Pattern; import javax.annotation.Nonnull; @@ -10,13 +11,14 @@ * This factory holds a list of all the registered factories for the various types of nodes. */ public class ParseNodeFactoryRegistry implements ParseNodeFactory { - /** Default singleton instance of the registry to be used when registring new factories that should be available by default. */ + /** Default singleton instance of the registry to be used when registering new factories that should be available by default. */ public static final ParseNodeFactoryRegistry defaultInstance = new ParseNodeFactoryRegistry(); /** List of factories that are registered by content type. */ public HashMap contentTypeAssociatedFactories = new HashMap<>(); public String getValidContentType() { throw new UnsupportedOperationException("The registry supports multiple content types. Get the registered factory instead."); } + private static Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); @Override @Nonnull public ParseNode getParseNode(@Nonnull final String contentType, @Nonnull final InputStream rawResponse) { @@ -25,10 +27,14 @@ public ParseNode getParseNode(@Nonnull final String contentType, @Nonnull final if(contentType.isEmpty()) { throw new NullPointerException("contentType cannot be empty"); } - if(contentTypeAssociatedFactories.containsKey(contentType)) { - return contentTypeAssociatedFactories.get(contentType).getParseNode(contentType, rawResponse); - } else { - throw new RuntimeException("Content type " + contentType + " does not have a factory to be parsed"); + final String vendorSpecificContentType = contentType.split(";")[0]; + if(contentTypeAssociatedFactories.containsKey(vendorSpecificContentType)) { + return contentTypeAssociatedFactories.get(vendorSpecificContentType).getParseNode(vendorSpecificContentType, rawResponse); } + final String cleanedContentType = contentTypeVendorCleanupPattern.matcher(vendorSpecificContentType).replaceAll(""); + if(contentTypeAssociatedFactories.containsKey(cleanedContentType)) { + return contentTypeAssociatedFactories.get(cleanedContentType).getParseNode(cleanedContentType, rawResponse); + } + throw new RuntimeException("Content type " + cleanedContentType + " does not have a factory to be parsed"); } } diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 08eee5e7af..ae9392cc17 100644 --- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -2,6 +2,7 @@ import java.util.HashMap; import java.util.Objects; +import java.util.regex.Pattern; import javax.annotation.Nonnull; /** This factory holds a list of all the registered factories for the various types of nodes. */ @@ -13,6 +14,7 @@ public class SerializationWriterFactoryRegistry implements SerializationWriterFa public String getValidContentType() { throw new UnsupportedOperationException("The registry supports multiple content types. Get the registered factory instead."); } + private static Pattern contentTypeVendorCleanupPattern = Pattern.compile("[^/]+\\+", Pattern.CASE_INSENSITIVE); @Override @Nonnull public SerializationWriter getSerializationWriter(@Nonnull final String contentType) { @@ -20,11 +22,15 @@ public SerializationWriter getSerializationWriter(@Nonnull final String contentT if(contentType.isEmpty()) { throw new NullPointerException("contentType cannot be empty"); } - if(contentTypeAssociatedFactories.containsKey(contentType)) { - return contentTypeAssociatedFactories.get(contentType).getSerializationWriter(contentType); - } else { - throw new RuntimeException("Content type " + contentType + " does not have a factory to be serialized"); + final String vendorSpecificContentType = contentType.split(";")[0]; + if(contentTypeAssociatedFactories.containsKey(vendorSpecificContentType)) { + return contentTypeAssociatedFactories.get(vendorSpecificContentType).getSerializationWriter(vendorSpecificContentType); } + final String cleanedContentType = contentTypeVendorCleanupPattern.matcher(vendorSpecificContentType).replaceAll(""); + if(contentTypeAssociatedFactories.containsKey(cleanedContentType)) { + return contentTypeAssociatedFactories.get(cleanedContentType).getSerializationWriter(cleanedContentType); + } + throw new RuntimeException("Content type " + contentType + " does not have a factory to be serialized"); } } diff --git a/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java b/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java new file mode 100644 index 0000000000..aacc45fa2a --- /dev/null +++ b/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java @@ -0,0 +1,34 @@ +package com.microsoft.kiota; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +import com.microsoft.kiota.serialization.ParseNodeFactoryRegistry; +import com.microsoft.kiota.serialization.ParseNode; +import com.microsoft.kiota.serialization.ParseNodeFactory; + +class ParseNodeFactoryRegistryTest { + @Test + void getsVendorSpecificParseNodeFactory() throws IOException { + final var registry = new ParseNodeFactoryRegistry(); + final var parseNodeFactoryMock = mock(ParseNodeFactory.class); + final var parseNodeMock = mock(ParseNode.class); + when(parseNodeFactoryMock.getValidContentType()).thenReturn("application/json"); + when(parseNodeFactoryMock.getParseNode(anyString(), any(InputStream.class))).thenReturn(parseNodeMock); + final var str = "{\"test\":\"test\"}"; + try (final var payloadMock = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))) { + registry.contentTypeAssociatedFactories.put("application/json", parseNodeFactoryMock); + final var parseNode = registry.getParseNode("application/vnd+json", payloadMock); + assertNotNull(parseNode); + } + } +} diff --git a/abstractions/java/lib/src/test/java/com/microsoft/kiota/SerializationWriterFactoryRegistryTest.java b/abstractions/java/lib/src/test/java/com/microsoft/kiota/SerializationWriterFactoryRegistryTest.java new file mode 100644 index 0000000000..12dbb97293 --- /dev/null +++ b/abstractions/java/lib/src/test/java/com/microsoft/kiota/SerializationWriterFactoryRegistryTest.java @@ -0,0 +1,27 @@ +package com.microsoft.kiota; + +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; + +import com.microsoft.kiota.serialization.SerializationWriterFactoryRegistry; +import com.microsoft.kiota.serialization.SerializationWriter; +import com.microsoft.kiota.serialization.SerializationWriterFactory; + +class SerializationWriterFactoryRegistryTest { + @Test + void getsVendorSpecificSerializationWriterFactory() throws IOException { + final var registry = new SerializationWriterFactoryRegistry(); + final var serializationWriterFactoryMock = mock(SerializationWriterFactory.class); + final var serializationWriterMock = mock(SerializationWriter.class); + when(serializationWriterFactoryMock.getValidContentType()).thenReturn("application/json"); + when(serializationWriterFactoryMock.getSerializationWriter(anyString())).thenReturn(serializationWriterMock); + registry.contentTypeAssociatedFactories.put("application/json", serializationWriterFactoryMock); + final var parseNode = registry.getSerializationWriter("application/vnd+json"); + assertNotNull(parseNode); + } +} From 38f0c3e79af3a2be31ecb38fa48a61053183c7e6 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 13:47:38 -0400 Subject: [PATCH 3/6] - adds vendor specific serialization support for Go --- abstractions/go/api_client_builder_test.go | 12 ++ .../parse_node_factory_registry.go | 23 +++- .../serialization_writer_factory_registry.go | 18 ++- ...ialization_writer_factory_registry_test.go | 123 ++++++++++++++++++ 4 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 abstractions/go/serialization/serialization_writer_factory_registry_test.go diff --git a/abstractions/go/api_client_builder_test.go b/abstractions/go/api_client_builder_test.go index 2921f6fbd7..c0ff4b1a85 100644 --- a/abstractions/go/api_client_builder_test.go +++ b/abstractions/go/api_client_builder_test.go @@ -17,6 +17,12 @@ func (*mockSerializer) WriteStringValue(key string, value *string) error { func (*mockSerializer) WriteBoolValue(key string, value *bool) error { return nil } +func (*mockSerializer) WriteByteValue(key string, value *byte) error { + return nil +} +func (*mockSerializer) WriteInt8Value(key string, value *int8) error { + return nil +} func (*mockSerializer) WriteInt32Value(key string, value *int32) error { return nil } @@ -59,6 +65,12 @@ func (*mockSerializer) WriteCollectionOfStringValues(key string, collection []st func (*mockSerializer) WriteCollectionOfBoolValues(key string, collection []bool) error { return nil } +func (*mockSerializer) WriteCollectionOfByteValues(key string, collection []byte) error { + return nil +} +func (*mockSerializer) WriteCollectionOfInt8Values(key string, collection []int8) error { + return nil +} func (*mockSerializer) WriteCollectionOfInt32Values(key string, collection []int32) error { return nil } diff --git a/abstractions/go/serialization/parse_node_factory_registry.go b/abstractions/go/serialization/parse_node_factory_registry.go index 9fc5661fce..f1b56ae4c7 100644 --- a/abstractions/go/serialization/parse_node_factory_registry.go +++ b/abstractions/go/serialization/parse_node_factory_registry.go @@ -1,6 +1,10 @@ package serialization -import "errors" +import ( + "errors" + re "regexp" + "strings" +) // ParseNodeFactoryRegistry holds a list of all the registered factories for the various types of nodes. type ParseNodeFactoryRegistry struct { @@ -17,6 +21,8 @@ func (m *ParseNodeFactoryRegistry) GetValidContentType() (string, error) { return "", errors.New("the registry supports multiple content types. Get the registered factory instead") } +var contentTypeVendorCleanupPattern = re.MustCompile("[^/]+\\+") + // GetRootParseNode returns a new ParseNode instance that is the root of the content func (m *ParseNodeFactoryRegistry) GetRootParseNode(contentType string, content []byte) (ParseNode, error) { if contentType == "" { @@ -25,10 +31,15 @@ func (m *ParseNodeFactoryRegistry) GetRootParseNode(contentType string, content if content == nil { return nil, errors.New("content is required") } - factory, ok := m.ContentTypeAssociatedFactories[contentType] - if !ok { - return nil, errors.New("content type " + contentType + " does not have a factory registered to be parsed") - } else { - return factory.GetRootParseNode(contentType, content) + vendorSpecificContentType := strings.Split(contentType, ";")[0] + factory, ok := m.ContentTypeAssociatedFactories[vendorSpecificContentType] + if ok { + return factory.GetRootParseNode(vendorSpecificContentType, content) + } + cleanedContentType := contentTypeVendorCleanupPattern.ReplaceAllString(vendorSpecificContentType, "") + factory, ok = m.ContentTypeAssociatedFactories[cleanedContentType] + if ok { + return factory.GetRootParseNode(cleanedContentType, content) } + return nil, errors.New("content type " + cleanedContentType + " does not have a factory registered to be parsed") } diff --git a/abstractions/go/serialization/serialization_writer_factory_registry.go b/abstractions/go/serialization/serialization_writer_factory_registry.go index 16169c1f92..13559adc63 100644 --- a/abstractions/go/serialization/serialization_writer_factory_registry.go +++ b/abstractions/go/serialization/serialization_writer_factory_registry.go @@ -1,6 +1,9 @@ package serialization -import "errors" +import ( + "errors" + "strings" +) // SerializationWriterFactoryRegistry is a factory holds a list of all the registered factories for the various types of nodes. type SerializationWriterFactoryRegistry struct { @@ -23,10 +26,15 @@ func (m *SerializationWriterFactoryRegistry) GetSerializationWriter(contentType if contentType == "" { return nil, errors.New("the content type is empty") } - factory := m.ContentTypeAssociatedFactories[contentType] - if factory == nil { - return nil, errors.New("Content type " + contentType + " does not have a factory registered to be parsed") - } else { + vendorSpecificContentType := strings.Split(contentType, ";")[0] + factory, ok := m.ContentTypeAssociatedFactories[vendorSpecificContentType] + if ok { return factory.GetSerializationWriter(contentType) } + cleanedContentType := contentTypeVendorCleanupPattern.ReplaceAllString(vendorSpecificContentType, "") + factory, ok = m.ContentTypeAssociatedFactories[cleanedContentType] + if ok { + return factory.GetSerializationWriter(cleanedContentType) + } + return nil, errors.New("Content type " + cleanedContentType + " does not have a factory registered to be parsed") } diff --git a/abstractions/go/serialization/serialization_writer_factory_registry_test.go b/abstractions/go/serialization/serialization_writer_factory_registry_test.go new file mode 100644 index 0000000000..e1a52c8c1c --- /dev/null +++ b/abstractions/go/serialization/serialization_writer_factory_registry_test.go @@ -0,0 +1,123 @@ +package serialization + +import ( + assert "github.com/stretchr/testify/assert" + "testing" + "github.com/stretchr/testify/mock" +) +type mockSerializer struct { +} + +func (*mockSerializer) WriteStringValue(key string, value *string) error { + return nil +} +func (*mockSerializer) WriteBoolValue(key string, value *bool) error { + return nil +} +func (*mockSerializer) WriteByteValue(key string, value *byte) error { + return nil +} +func (*mockSerializer) WriteInt8Value(key string, value *int8) error { + return nil +} +func (*mockSerializer) WriteInt32Value(key string, value *int32) error { + return nil +} +func (*mockSerializer) WriteInt64Value(key string, value *int64) error { + return nil +} +func (*mockSerializer) WriteFloat32Value(key string, value *float32) error { + return nil +} +func (*mockSerializer) WriteFloat64Value(key string, value *float64) error { + return nil +} +func (*mockSerializer) WriteByteArrayValue(key string, value []byte) error { + return nil +} +func (*mockSerializer) WriteTimeValue(key string, value *time.Time) error { + return nil +} +func (*mockSerializer) WriteISODurationValue(key string, value *serialization.ISODuration) error { + return nil +} +func (*mockSerializer) WriteDateOnlyValue(key string, value *serialization.DateOnly) error { + return nil +} +func (*mockSerializer) WriteTimeOnlyValue(key string, value *serialization.TimeOnly) error { + return nil +} +func (*mockSerializer) WriteUUIDValue(key string, value *uuid.UUID) error { + return nil +} +func (*mockSerializer) WriteObjectValue(key string, item serialization.Parsable) error { + return nil +} +func (*mockSerializer) WriteCollectionOfObjectValues(key string, collection []serialization.Parsable) error { + return nil +} +func (*mockSerializer) WriteCollectionOfStringValues(key string, collection []string) error { + return nil +} +func (*mockSerializer) WriteCollectionOfBoolValues(key string, collection []bool) error { + return nil +} +func (*mockSerializer) WriteCollectionOfByteValues(key string, collection []byte) error { + return nil +} +func (*mockSerializer) WriteCollectionOfInt8Values(key string, collection []int8) error { + return nil +} +func (*mockSerializer) WriteCollectionOfInt32Values(key string, collection []int32) error { + return nil +} +func (*mockSerializer) WriteCollectionOfInt64Values(key string, collection []int64) error { + return nil +} +func (*mockSerializer) WriteCollectionOfFloat32Values(key string, collection []float32) error { + return nil +} +func (*mockSerializer) WriteCollectionOfFloat64Values(key string, collection []float64) error { + return nil +} +func (*mockSerializer) WriteCollectionOfTimeValues(key string, collection []time.Time) error { + return nil +} +func (*mockSerializer) WriteCollectionOfISODurationValues(key string, collection []serialization.ISODuration) error { + return nil +} +func (*mockSerializer) WriteCollectionOfDateOnlyValues(key string, collection []serialization.DateOnly) error { + return nil +} +func (*mockSerializer) WriteCollectionOfTimeOnlyValues(key string, collection []serialization.TimeOnly) error { + return nil +} +func (*mockSerializer) WriteCollectionOfUUIDValues(key string, collection []uuid.UUID) error { + return nil +} +func (*mockSerializer) GetSerializedContent() ([]byte, error) { + return nil, nil +} +func (*mockSerializer) WriteAdditionalData(value map[string]interface{}) error { + return nil +} +func (*mockSerializer) Close() error { + return nil +} + +type mockSerializerFactory struct { +} + +func (*mockSerializerFactory) GetValidContentType() (string, error) { + return "application/json", nil +} +func (*mockSerializerFactory) GetSerializationWriter(contentType string) (serialization.SerializationWriter, error) { + return &mockSerializer{}, nil +} + +func TestItGetsVendorSpecificSerializationWriter(t *testing.T) { + registry := NewSerializationWriterFactoryRegistry() + registry.ContentTypeAssociatedFactories["application/json"] = &mockSerializerFactory{} + serializationWriter = registry.GetSerializationWriter("application/vnd+json") + assert.NotNil(t, serializationWriter) +} From a0686b57bc264d3e86f4e5059c8eb5d3432f2953 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 13:48:05 -0400 Subject: [PATCH 4/6] - code linting --- .../kiota/serialization/SerializationWriterFactoryRegistry.java | 2 +- .../java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java | 2 +- .../abstractions/serialization/parse_node_factory_registry.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index ae9392cc17..ab0e50c530 100644 --- a/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/abstractions/java/lib/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -7,7 +7,7 @@ import javax.annotation.Nonnull; /** This factory holds a list of all the registered factories for the various types of nodes. */ public class SerializationWriterFactoryRegistry implements SerializationWriterFactory { - /** Default singleton instance of the registry to be used when registring new factories that should be available by default. */ + /** Default singleton instance of the registry to be used when registering new factories that should be available by default. */ public final static SerializationWriterFactoryRegistry defaultInstance = new SerializationWriterFactoryRegistry(); /** List of factories that are registered by content type. */ public HashMap contentTypeAssociatedFactories = new HashMap<>(); diff --git a/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java b/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java index aacc45fa2a..e1c96e2d33 100644 --- a/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java +++ b/abstractions/java/lib/src/test/java/com/microsoft/kiota/ParseNodeFactoryRegistryTest.java @@ -24,9 +24,9 @@ void getsVendorSpecificParseNodeFactory() throws IOException { final var parseNodeMock = mock(ParseNode.class); when(parseNodeFactoryMock.getValidContentType()).thenReturn("application/json"); when(parseNodeFactoryMock.getParseNode(anyString(), any(InputStream.class))).thenReturn(parseNodeMock); + registry.contentTypeAssociatedFactories.put("application/json", parseNodeFactoryMock); final var str = "{\"test\":\"test\"}"; try (final var payloadMock = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8))) { - registry.contentTypeAssociatedFactories.put("application/json", parseNodeFactoryMock); final var parseNode = registry.getParseNode("application/vnd+json", payloadMock); assertNotNull(parseNode); } diff --git a/abstractions/python/kiota/abstractions/serialization/parse_node_factory_registry.py b/abstractions/python/kiota/abstractions/serialization/parse_node_factory_registry.py index 54f60db0dd..1bebb0a7df 100644 --- a/abstractions/python/kiota/abstractions/serialization/parse_node_factory_registry.py +++ b/abstractions/python/kiota/abstractions/serialization/parse_node_factory_registry.py @@ -15,7 +15,7 @@ class ParseNodeFactoryRegistry(ParseNodeFactory): __instance = None def __new__(cls, *args, **kwargs): - """Default singleton instance of the registry to be used when registring new + """Default singleton instance of the registry to be used when registering new factories that should be available by default. Returns: From b4b40484db69fdf270a01b91c0f8392485421bbc Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 13:49:23 -0400 Subject: [PATCH 5/6] - adds changelog entry for vendor specific support --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3f82e7821..4aeaa78b55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added support for vendor specific content types generation/serialization. [#1197](https://github.com/microsoft/kiota/issues/1197) - Adds support for 204 no content in generation and CSharp/Java/Go/TypeScript request adapters. #1410 ### Changed From 04cbbe45352d6c611cd02b29f6e182a88aebbab2 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Tue, 29 Mar 2022 13:50:18 -0400 Subject: [PATCH 6/6] - bumps java abstractions for vendor specific support --- abstractions/java/lib/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abstractions/java/lib/build.gradle b/abstractions/java/lib/build.gradle index 646767e872..38d3dc780c 100644 --- a/abstractions/java/lib/build.gradle +++ b/abstractions/java/lib/build.gradle @@ -49,7 +49,7 @@ publishing { publications { gpr(MavenPublication) { artifactId 'kiota-abstractions' - version '1.0.29' + version '1.0.30' from(components.java) } }