From 867953cbd0523cd8d146a5f3a522cd8652ccd924 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Thu, 3 Oct 2024 22:52:09 +0300 Subject: [PATCH 01/12] feat: Adds overload to serialization proxy factories to configure serialization of all values in backed models --- .../SerializationWriterFactoryRegistry.java | 92 +++++++++++++++++-- .../SerializationWriterProxyFactory.java | 2 +- ...gStoreSerializationWriterProxyFactory.java | 18 ++++ 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 0c4b5879c..639f9620d 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -1,5 +1,7 @@ package com.microsoft.kiota.serialization; +import com.microsoft.kiota.store.BackingStoreSerializationWriterProxyFactory; + import jakarta.annotation.Nonnull; import java.util.HashMap; @@ -36,20 +38,92 @@ public SerializationWriterFactoryRegistry() { if (contentType.isEmpty()) { throw new NullPointerException("contentType cannot be empty"); } - final String vendorSpecificContentType = contentType.split(";")[0]; + final ContentTypeWrapper contentTypeWrapper = new ContentTypeWrapper(contentType); + final SerializationWriterFactory serializationWriterFactory = + getSerializationWriterFactory(contentTypeWrapper); + return serializationWriterFactory.getSerializationWriter( + contentTypeWrapper.cleanedContentType); + } + + /** + * Get a Serialization Writer with backing store configured with serializeOnlyChangedValues + * @param contentType + * @param serializeOnlyChangedValues control backing store functionality + * @return the serialization writer + */ + @Nonnull public SerializationWriter getSerializationWriter( + @Nonnull final String contentType, final boolean serializeOnlyChangedValues) { + if (!serializeOnlyChangedValues) { + final ContentTypeWrapper contentTypeWrapper = new ContentTypeWrapper(contentType); + final SerializationWriterFactory factory = + getSerializationWriterFactory(contentTypeWrapper); + if (factory instanceof BackingStoreSerializationWriterProxyFactory) { + return ((BackingStoreSerializationWriterProxyFactory) factory) + .getSerializationWriter( + contentTypeWrapper.cleanedContentType, serializeOnlyChangedValues); + } + } + return getSerializationWriter(contentType); + } + + /** + * Gets a SerializationWriterFactory that is mapped to a cleaned content type string + * @param contentTypeWrapper wrapper object carrying initial content type and result of parsing it + * @return the serialization writer factory + * @throws RuntimeException when no mapped factory is found + */ + @Nonnull private SerializationWriterFactory getSerializationWriterFactory( + @Nonnull final ContentTypeWrapper contentTypeWrapper) { + final String vendorSpecificContentType = + getVendorSpecificContentType(contentTypeWrapper.contentType); if (contentTypeAssociatedFactories.containsKey(vendorSpecificContentType)) { - return contentTypeAssociatedFactories - .get(vendorSpecificContentType) - .getSerializationWriter(vendorSpecificContentType); + contentTypeWrapper.cleanedContentType = vendorSpecificContentType; + return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); } final String cleanedContentType = - contentTypeVendorCleanupPattern.matcher(vendorSpecificContentType).replaceAll(""); + getCleanedVendorSpecificContentType(contentTypeWrapper.cleanedContentType); if (contentTypeAssociatedFactories.containsKey(cleanedContentType)) { - return contentTypeAssociatedFactories - .get(cleanedContentType) - .getSerializationWriter(cleanedContentType); + contentTypeWrapper.cleanedContentType = cleanedContentType; + return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); } throw new RuntimeException( - "Content type " + contentType + " does not have a factory to be serialized"); + "Content type " + + contentTypeWrapper.contentType + + " does not have a factory to be serialized"); + } + + /** + * Splits content type by ; and returns first segment or original contentType + * @param contentType + * @return vendor specific content type + */ + @Nonnull private String getVendorSpecificContentType(@Nonnull final String contentType) { + String[] split = contentType.split(";"); + if (split.length >= 1) { + return split[0]; + } + return contentType; + } + + /** + * Does a regex match on the content type replacing special characters + * @param contentType + * @return cleaned content type + */ + @Nonnull private String getCleanedVendorSpecificContentType(@Nonnull final String contentType) { + return contentTypeVendorCleanupPattern.matcher(contentType).replaceAll(""); + } + + /** + * Wrapper class to carry the cleaned version of content-type after parsing in multiple stages + */ + private static final class ContentTypeWrapper { + private String contentType; + private String cleanedContentType; + + ContentTypeWrapper(@Nonnull final String contentType) { + this.contentType = contentType; + this.cleanedContentType = ""; + } } } diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java index d45d80f89..46d556f8b 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java @@ -13,7 +13,7 @@ public abstract class SerializationWriterProxyFactory implements SerializationWr return _concrete.getValidContentType(); } - private final SerializationWriterFactory _concrete; + protected final SerializationWriterFactory _concrete; private final Consumer _onBefore; private final Consumer _onAfter; private final BiConsumer _onStart; diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java index a4681cb2a..f8c763123 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java @@ -1,5 +1,6 @@ package com.microsoft.kiota.store; +import com.microsoft.kiota.serialization.SerializationWriter; import com.microsoft.kiota.serialization.SerializationWriterFactory; import com.microsoft.kiota.serialization.SerializationWriterProxyFactory; @@ -48,4 +49,21 @@ public BackingStoreSerializationWriterProxyFactory( } }); } + + /** + * Returns a SerializationWriter that overrides the default serialization of only changed values if serializeOnlyChangedValues="true" + * Gets the previously proxied serialization writer without any backing store configuration to prevent overwriting the registry affecting + * future serialization requests + * + * @param contentType HTTP content type header value + * @param serializeOnlyChangedValues alter backing store default behavior + * @return the SerializationWriter + */ + @Nonnull public SerializationWriter getSerializationWriter( + @Nonnull final String contentType, final boolean serializeOnlyChangedValues) { + if (!serializeOnlyChangedValues) { + return _concrete.getSerializationWriter(contentType); + } + return getSerializationWriter(contentType); + } } From 0006ff8538e2c26692c4e2f3238fadaec1436027 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Thu, 3 Oct 2024 23:36:48 +0300 Subject: [PATCH 02/12] feat: Adds overloads to serialization helper methods with backing store serialization configuration options --- .../serialization/KiotaJsonSerialization.java | 58 ++++++++++++ .../serialization/KiotaSerialization.java | 93 +++++++++++++++++-- 2 files changed, 144 insertions(+), 7 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java index 046c81019..ddf229f88 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java @@ -26,6 +26,20 @@ private KiotaJsonSerialization() {} return KiotaSerialization.serializeAsStream(CONTENT_TYPE, value); } + /** + * Serializes the given value to a stream + * @param the type of the value to serialize + * @param value the value to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a stream + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static InputStream serializeAsStream( + @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { + return KiotaSerialization.serializeAsStream( + CONTENT_TYPE, value, serializeOnlyChangedValues); + } + /** * Serializes the given value to a string * @param the type of the value to serialize @@ -38,6 +52,20 @@ private KiotaJsonSerialization() {} return KiotaSerialization.serializeAsString(CONTENT_TYPE, value); } + /** + * Serializes the given value to a string + * @param the type of the value to serialize + * @param value the value to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a string + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static String serializeAsString( + @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { + return KiotaSerialization.serializeAsString( + CONTENT_TYPE, value, serializeOnlyChangedValues); + } + /** * Serializes the given value to a stream * @param the type of the value to serialize @@ -50,6 +78,21 @@ private KiotaJsonSerialization() {} return KiotaSerialization.serializeAsStream(CONTENT_TYPE, values); } + /** + * Serializes the given value to a stream + * @param the type of the value to serialize + * @param values the values to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a stream + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static InputStream serializeAsStream( + @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) + throws IOException { + return KiotaSerialization.serializeAsStream( + CONTENT_TYPE, values, serializeOnlyChangedValues); + } + /** * Serializes the given value to a string * @param the type of the value to serialize @@ -62,6 +105,21 @@ private KiotaJsonSerialization() {} return KiotaSerialization.serializeAsString(CONTENT_TYPE, values); } + /** + * Serializes the given value to a string + * @param the type of the value to serialize + * @param values the values to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a string + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static String serializeAsString( + @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) + throws IOException { + return KiotaSerialization.serializeAsString( + CONTENT_TYPE, values, serializeOnlyChangedValues); + } + /** * Deserializes the given stream to a model object * @param the type of the value to deserialize diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java index e7b06eb13..a9c0a9e0e 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java @@ -16,6 +16,7 @@ */ public final class KiotaSerialization { private static final String CHARSET_NAME = "UTF-8"; + private static final boolean DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES = true; private KiotaSerialization() {} @@ -29,7 +30,26 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, @Nonnull final T value) throws IOException { - try (final SerializationWriter writer = getSerializationWriter(contentType, value)) { + return serializeAsStream(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + } + + /** + * Serializes the given value to a stream and configures returned values by the backing store if available + * @param the type of the value to serialize + * @param contentType the content type to use for serialization + * @param value the value to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a stream + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static InputStream serializeAsStream( + @Nonnull final String contentType, + @Nonnull final T value, + final boolean serializeOnlyChangedValues) + throws IOException { + Objects.requireNonNull(value); + try (final SerializationWriter writer = + getSerializationWriter(contentType, serializeOnlyChangedValues)) { writer.writeObjectValue("", value); return writer.getSerializedContent(); } @@ -45,7 +65,27 @@ private KiotaSerialization() {} */ @Nonnull public static String serializeAsString( @Nonnull final String contentType, @Nonnull final T value) throws IOException { - try (final InputStream stream = serializeAsStream(contentType, value)) { + Objects.requireNonNull(value); + return serializeAsString(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + } + + /** + * Serializes the given value to a string + * @param the type of the value to serialize + * @param contentType the content type to use for serialization + * @param value the value to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a string + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static String serializeAsString( + @Nonnull final String contentType, + @Nonnull final T value, + final boolean serializeOnlyChangedValues) + throws IOException { + Objects.requireNonNull(value); + try (final InputStream stream = + serializeAsStream(contentType, value, serializeOnlyChangedValues)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } @@ -61,7 +101,27 @@ private KiotaSerialization() {} @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { - try (final SerializationWriter writer = getSerializationWriter(contentType, values)) { + Objects.requireNonNull(values); + return serializeAsStream(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + } + + /** + * Serializes the given value to a stream + * @param the type of the value to serialize + * @param contentType the content type to use for serialization + * @param values the values to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a stream + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static InputStream serializeAsStream( + @Nonnull final String contentType, + @Nonnull final Iterable values, + final boolean serializeOnlyChangedValues) + throws IOException { + Objects.requireNonNull(values); + try (final SerializationWriter writer = + getSerializationWriter(contentType, serializeOnlyChangedValues)) { writer.writeCollectionOfObjectValues("", values); return writer.getSerializedContent(); } @@ -78,20 +138,39 @@ private KiotaSerialization() {} @Nonnull public static String serializeAsString( @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { - try (final InputStream stream = serializeAsStream(contentType, values)) { + Objects.requireNonNull(values); + return serializeAsString(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + } + + /** + * Serializes the given value to a string + * @param the type of the value to serialize + * @param contentType the content type to use for serialization + * @param values the values to serialize + * @param serializeOnlyChangedValues whether to serialize all values in value if value is a BackedModel + * @return the serialized value as a string + * @throws IOException when the stream cannot be closed or read. + */ + @Nonnull public static String serializeAsString( + @Nonnull final String contentType, + @Nonnull final Iterable values, + final boolean serializeOnlyChangedValues) + throws IOException { + Objects.requireNonNull(values); + try (final InputStream stream = + serializeAsStream(contentType, values, serializeOnlyChangedValues)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } private static SerializationWriter getSerializationWriter( - @Nonnull final String contentType, @Nonnull final Object value) { + @Nonnull final String contentType, final boolean serializeOnlyChangedValues) { Objects.requireNonNull(contentType); - Objects.requireNonNull(value); if (contentType.isEmpty()) { throw new NullPointerException("content type cannot be empty"); } return SerializationWriterFactoryRegistry.defaultInstance.getSerializationWriter( - contentType); + contentType, serializeOnlyChangedValues); } /** From 1a6738b10f08b859cbbff1d61f1885eb29deff1c Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 16:39:44 +0300 Subject: [PATCH 03/12] Add unit tests --- .../abstractions/gradle/dependencies.gradle | 1 + .../abstractions/spotBugsExcludeFilter.xml | 6 +- .../SerializationHelpersTest.java | 57 ++++++ .../mocks/TestBackedModelEntity.java | 168 ++++++++++++++++++ 4 files changed, 228 insertions(+), 4 deletions(-) create mode 100644 components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java diff --git a/components/abstractions/gradle/dependencies.gradle b/components/abstractions/gradle/dependencies.gradle index 0974823cd..f864b5307 100644 --- a/components/abstractions/gradle/dependencies.gradle +++ b/components/abstractions/gradle/dependencies.gradle @@ -3,6 +3,7 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.11.1' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.11.1' testImplementation 'org.mockito:mockito-core:5.14.1' + testImplementation project(':components:serialization:json') // Use JUnit Jupiter Engine for testing. testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine' diff --git a/components/abstractions/spotBugsExcludeFilter.xml b/components/abstractions/spotBugsExcludeFilter.xml index e2dbb38ce..68e65df88 100644 --- a/components/abstractions/spotBugsExcludeFilter.xml +++ b/components/abstractions/spotBugsExcludeFilter.xml @@ -46,13 +46,11 @@ xsi:schemaLocation="https://github.com/spotbugs/filter/3.0.0 https://raw.githubu - - - - + + diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java index 427605cef..a43f5b191 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java @@ -1,6 +1,7 @@ package com.microsoft.kiota.serialization; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -9,13 +10,16 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.microsoft.kiota.serialization.mocks.TestBackedModelEntity; import com.microsoft.kiota.serialization.mocks.TestEntity; +import com.microsoft.kiota.store.BackingStoreSerializationWriterProxyFactory; import org.junit.jupiter.api.Test; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; class SerializationHelpersTest { private static final String _jsonContentType = "application/json"; @@ -91,4 +95,57 @@ void serializesObjectCollection() throws IOException { assertEquals("[{'id':'123'}]", result); verify(mockSerializationWriter, times(1)).writeCollectionOfObjectValues(eq(""), any()); } + + @Test + void serializesAllValuesInBackedModel() throws IOException { + final BackingStoreSerializationWriterProxyFactory + backingStoreSerializationWriterProxyFactory = + new BackingStoreSerializationWriterProxyFactory( + new JsonSerializationWriterFactory()); + SerializationWriterFactoryRegistry.defaultInstance.contentTypeAssociatedFactories.put( + _jsonContentType, backingStoreSerializationWriterProxyFactory); + + final TestBackedModelEntity entity = new TestBackedModelEntity(); + entity.setId("123"); + entity.setOfficeLocation("Nairobi"); + + entity.getBackingStore().setIsInitializationCompleted(true); + + final String result = KiotaJsonSerialization.serializeAsString(entity, false); + + assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); + assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", result); + + final String collectionResult = + KiotaJsonSerialization.serializeAsString( + new ArrayList<>(Arrays.asList(entity)), false); + + assertEquals("[{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}]", collectionResult); + } + + @Test + void serializesChangedValuesInBackedModel() throws IOException { + final BackingStoreSerializationWriterProxyFactory + backingStoreSerializationWriterProxyFactory = + new BackingStoreSerializationWriterProxyFactory( + new JsonSerializationWriterFactory()); + SerializationWriterFactoryRegistry.defaultInstance.contentTypeAssociatedFactories.put( + _jsonContentType, backingStoreSerializationWriterProxyFactory); + + final TestBackedModelEntity entity = new TestBackedModelEntity(); + entity.setId("123"); + entity.setOfficeLocation("Nairobi"); + + entity.getBackingStore().setIsInitializationCompleted(true); + + final String result = KiotaJsonSerialization.serializeAsString(entity, true); + + assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); + assertEquals("{}", result); + + final String collectionResult = + KiotaJsonSerialization.serializeAsString( + new ArrayList<>(Arrays.asList(entity)), true); + assertEquals("[{}]", collectionResult); + } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java new file mode 100644 index 000000000..a993a701a --- /dev/null +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java @@ -0,0 +1,168 @@ +package com.microsoft.kiota.serialization.mocks; + +import com.microsoft.kiota.PeriodAndDuration; +import com.microsoft.kiota.serialization.AdditionalDataHolder; +import com.microsoft.kiota.serialization.Parsable; +import com.microsoft.kiota.serialization.ParseNode; +import com.microsoft.kiota.serialization.SerializationWriter; +import com.microsoft.kiota.store.BackedModel; +import com.microsoft.kiota.store.BackingStore; +import com.microsoft.kiota.store.BackingStoreFactorySingleton; + +import jakarta.annotation.Nonnull; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Consumer; + +public class TestBackedModelEntity implements Parsable, AdditionalDataHolder, BackedModel { + private BackingStore backingStore; + + public TestBackedModelEntity() { + backingStore = BackingStoreFactorySingleton.instance.createBackingStore(); + } + + public String getId() { + return this.backingStore.get("id"); + } + + public void setId(String _id) { + this.backingStore.set("id", _id); + } + + public String getOfficeLocation() { + return this.backingStore.get("officeLocation"); + } + + public void setOfficeLocation(String _officeLocation) { + this.backingStore.set("officeLocation", _officeLocation); + } + + public LocalDate getBirthDay() { + return this.backingStore.get("birthDay"); + } + + public void setBirthDay(LocalDate value) { + this.backingStore.set("birthDay", value); + } + + public PeriodAndDuration getWorkDuration() { + return this.backingStore.get("workDuration"); + } + + public void setWorkDuration(PeriodAndDuration value) { + this.backingStore.set("workDuration", PeriodAndDuration.ofPeriodAndDuration(value)); + } + + public LocalTime getStartWorkTime() { + return this.backingStore.get("startWorkTime"); + } + + public void setStartWorkTime(LocalTime value) { + this.backingStore.set("startWorkTime", value); + } + + public LocalTime getEndWorkTime() { + return this.backingStore.get("endWorkTime"); + } + + public void setEndWorkTime(LocalTime value) { + this.backingStore.set("endWorkTime", value); + } + + public OffsetDateTime getCreatedDateTime() { + return this.backingStore.get("createdDateTime"); + } + + public void setCreatedDateTime(OffsetDateTime value) { + this.backingStore.set("createdDateTime", value); + } + + @Nonnull @Override + public Map> getFieldDeserializers() { + return new HashMap<>() { + { + put( + "id", + (n) -> { + setId(n.getStringValue()); + }); + put( + "officeLocation", + (n) -> { + setOfficeLocation(n.getStringValue()); + }); + put( + "birthDay", + (n) -> { + setBirthDay(n.getLocalDateValue()); + }); + put( + "workDuration", + (n) -> { + setWorkDuration(n.getPeriodAndDurationValue()); + }); + put( + "startWorkTime", + (n) -> { + setStartWorkTime(n.getLocalTimeValue()); + }); + put( + "endWorkTime", + (n) -> { + setEndWorkTime(n.getLocalTimeValue()); + }); + put( + "createdDateTime", + (n) -> { + setCreatedDateTime(n.getOffsetDateTimeValue()); + }); + } + }; + } + + @Override + public void serialize(@Nonnull SerializationWriter writer) { + Objects.requireNonNull(writer); + writer.writeStringValue("id", getId()); + writer.writeStringValue("officeLocation", getOfficeLocation()); + writer.writeLocalDateValue("birthDay", getBirthDay()); + writer.writePeriodAndDurationValue("workDuration", getWorkDuration()); + writer.writeLocalTimeValue("startWorkTime", getStartWorkTime()); + writer.writeLocalTimeValue("endWorkTime", getEndWorkTime()); + writer.writeOffsetDateTimeValue("createdDateTime", getCreatedDateTime()); + writer.writeAdditionalData(getAdditionalData()); + } + + @Nonnull @Override + public Map getAdditionalData() { + Map value = this.backingStore.get("additionalData"); + if (value == null) { + value = new HashMap<>(); + this.setAdditionalData(value); + } + return value; + } + + /** + * Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well. + * @param value Value to set for the AdditionalData property. + */ + public void setAdditionalData(@jakarta.annotation.Nullable final Map value) { + this.backingStore.set("additionalData", value); + } + + @jakarta.annotation.Nonnull public static TestEntity createFromDiscriminatorValue( + @jakarta.annotation.Nonnull final ParseNode parseNode) { + return new TestEntity(); + } + + @Override + public BackingStore getBackingStore() { + return backingStore; + } +} From 3b96a3878f1d34db7d9559ce77324e10a64ba4b6 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 16:49:45 +0300 Subject: [PATCH 04/12] Use package-private wrapper properties --- .../serialization/SerializationWriterFactoryRegistry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 639f9620d..36477f4df 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -118,8 +118,8 @@ public SerializationWriterFactoryRegistry() { * Wrapper class to carry the cleaned version of content-type after parsing in multiple stages */ private static final class ContentTypeWrapper { - private String contentType; - private String cleanedContentType; + String contentType; + String cleanedContentType; ContentTypeWrapper(@Nonnull final String contentType) { this.contentType = contentType; From aac05d3ffe687976a428c69613007f78f165f86e Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 17:05:49 +0300 Subject: [PATCH 05/12] Fix android linting failures --- .../serialization/KiotaJsonSerialization.java | 16 +++++------ .../serialization/KiotaSerialization.java | 28 +++++++++---------- .../SerializationHelpersTest.java | 10 ++++--- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java index ddf229f88..1309d814d 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java @@ -35,9 +35,9 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { + final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { return KiotaSerialization.serializeAsStream( - CONTENT_TYPE, value, serializeOnlyChangedValues); + CONTENT_TYPE, serializeOnlyChangedValues, value); } /** @@ -61,9 +61,9 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { + final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { return KiotaSerialization.serializeAsString( - CONTENT_TYPE, value, serializeOnlyChangedValues); + CONTENT_TYPE, serializeOnlyChangedValues, value); } /** @@ -87,10 +87,10 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) throws IOException { return KiotaSerialization.serializeAsStream( - CONTENT_TYPE, values, serializeOnlyChangedValues); + CONTENT_TYPE, serializeOnlyChangedValues, values); } /** @@ -114,10 +114,10 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) throws IOException { return KiotaSerialization.serializeAsString( - CONTENT_TYPE, values, serializeOnlyChangedValues); + CONTENT_TYPE, serializeOnlyChangedValues, values); } /** diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java index a9c0a9e0e..11bb9ec90 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java @@ -30,7 +30,7 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, @Nonnull final T value) throws IOException { - return serializeAsStream(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + return serializeAsStream(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, value); } /** @@ -44,8 +44,8 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, - @Nonnull final T value, - final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, + @Nonnull final T value) throws IOException { Objects.requireNonNull(value); try (final SerializationWriter writer = @@ -66,7 +66,7 @@ private KiotaSerialization() {} @Nonnull public static String serializeAsString( @Nonnull final String contentType, @Nonnull final T value) throws IOException { Objects.requireNonNull(value); - return serializeAsString(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + return serializeAsString(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, value); } /** @@ -80,12 +80,12 @@ private KiotaSerialization() {} */ @Nonnull public static String serializeAsString( @Nonnull final String contentType, - @Nonnull final T value, - final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, + @Nonnull final T value) throws IOException { Objects.requireNonNull(value); try (final InputStream stream = - serializeAsStream(contentType, value, serializeOnlyChangedValues)) { + serializeAsStream(contentType, serializeOnlyChangedValues, value)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } @@ -102,7 +102,7 @@ private KiotaSerialization() {} @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); - return serializeAsStream(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + return serializeAsStream(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, values); } /** @@ -116,8 +116,8 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, - @Nonnull final Iterable values, - final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, + @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); try (final SerializationWriter writer = @@ -139,7 +139,7 @@ private KiotaSerialization() {} @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); - return serializeAsString(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); + return serializeAsString(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, values); } /** @@ -153,12 +153,12 @@ private KiotaSerialization() {} */ @Nonnull public static String serializeAsString( @Nonnull final String contentType, - @Nonnull final Iterable values, - final boolean serializeOnlyChangedValues) + final boolean serializeOnlyChangedValues, + @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); try (final InputStream stream = - serializeAsStream(contentType, values, serializeOnlyChangedValues)) { + serializeAsStream(contentType, serializeOnlyChangedValues, values)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java index a43f5b191..1e2f3bca2 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java @@ -111,14 +111,15 @@ void serializesAllValuesInBackedModel() throws IOException { entity.getBackingStore().setIsInitializationCompleted(true); - final String result = KiotaJsonSerialization.serializeAsString(entity, false); + final String result = KiotaJsonSerialization.serializeAsString(false, entity); assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", result); final String collectionResult = KiotaJsonSerialization.serializeAsString( - new ArrayList<>(Arrays.asList(entity)), false); + false, + new ArrayList<>(Arrays.asList(entity))); assertEquals("[{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}]", collectionResult); } @@ -138,14 +139,15 @@ void serializesChangedValuesInBackedModel() throws IOException { entity.getBackingStore().setIsInitializationCompleted(true); - final String result = KiotaJsonSerialization.serializeAsString(entity, true); + final String result = KiotaJsonSerialization.serializeAsString(true, entity); assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); assertEquals("{}", result); final String collectionResult = KiotaJsonSerialization.serializeAsString( - new ArrayList<>(Arrays.asList(entity)), true); + true, + new ArrayList<>(Arrays.asList(entity))); assertEquals("[{}]", collectionResult); } } From bc6edc44dab4310a403bd6353779e7bde025a71f Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 17:45:33 +0300 Subject: [PATCH 06/12] Increase test coverage --- .../SerializationWriterFactoryRegistry.java | 2 +- .../SerializationHelpersTest.java | 24 ++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 36477f4df..23f82768b 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -81,7 +81,7 @@ public SerializationWriterFactoryRegistry() { return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); } final String cleanedContentType = - getCleanedVendorSpecificContentType(contentTypeWrapper.cleanedContentType); + getCleanedVendorSpecificContentType(vendorSpecificContentType); if (contentTypeAssociatedFactories.containsKey(cleanedContentType)) { contentTypeWrapper.cleanedContentType = cleanedContentType; return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java index 1e2f3bca2..35d19d506 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java @@ -109,6 +109,7 @@ void serializesAllValuesInBackedModel() throws IOException { entity.setId("123"); entity.setOfficeLocation("Nairobi"); + // Sets the backing store to be initialized. No properties are dirty entity.getBackingStore().setIsInitializationCompleted(true); final String result = KiotaJsonSerialization.serializeAsString(false, entity); @@ -136,7 +137,6 @@ void serializesChangedValuesInBackedModel() throws IOException { final TestBackedModelEntity entity = new TestBackedModelEntity(); entity.setId("123"); entity.setOfficeLocation("Nairobi"); - entity.getBackingStore().setIsInitializationCompleted(true); final String result = KiotaJsonSerialization.serializeAsString(true, entity); @@ -150,4 +150,26 @@ void serializesChangedValuesInBackedModel() throws IOException { new ArrayList<>(Arrays.asList(entity))); assertEquals("[{}]", collectionResult); } + + @Test + void cleansContentType() throws IOException { + final BackingStoreSerializationWriterProxyFactory + backingStoreSerializationWriterProxyFactory = + new BackingStoreSerializationWriterProxyFactory( + new JsonSerializationWriterFactory()); + SerializationWriterFactoryRegistry.defaultInstance.contentTypeAssociatedFactories.put( + _jsonContentType, backingStoreSerializationWriterProxyFactory); + + final TestBackedModelEntity entity = new TestBackedModelEntity(); + entity.setId("123"); + entity.setOfficeLocation("Nairobi"); + + final String result = KiotaSerialization.serializeAsString("application/json;odata.metadata=minimal", entity); + assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", result); + + // Because onAfterObjectSerialization, returnOnlyChangedValues is set to false & initialization is completed + entity.getBackingStore().setIsInitializationCompleted(false); + final String otherResult = KiotaSerialization.serializeAsString("application/vnd.github.raw+json", entity); + assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", otherResult); + } } From 0c843abb17325445d4768a4dfaf1ce6a599e096a Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 17:54:32 +0300 Subject: [PATCH 07/12] Fix spotless failures --- .../serialization/KiotaJsonSerialization.java | 8 ++++---- .../serialization/SerializationHelpersTest.java | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java index 1309d814d..87eb2e836 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java @@ -35,7 +35,7 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { + final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { return KiotaSerialization.serializeAsStream( CONTENT_TYPE, serializeOnlyChangedValues, value); } @@ -61,7 +61,7 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { + final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { return KiotaSerialization.serializeAsString( CONTENT_TYPE, serializeOnlyChangedValues, value); } @@ -87,7 +87,7 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) + final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) throws IOException { return KiotaSerialization.serializeAsStream( CONTENT_TYPE, serializeOnlyChangedValues, values); @@ -114,7 +114,7 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) + final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) throws IOException { return KiotaSerialization.serializeAsString( CONTENT_TYPE, serializeOnlyChangedValues, values); diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java index 35d19d506..49add4c63 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java @@ -119,8 +119,7 @@ void serializesAllValuesInBackedModel() throws IOException { final String collectionResult = KiotaJsonSerialization.serializeAsString( - false, - new ArrayList<>(Arrays.asList(entity))); + false, new ArrayList<>(Arrays.asList(entity))); assertEquals("[{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}]", collectionResult); } @@ -146,8 +145,7 @@ void serializesChangedValuesInBackedModel() throws IOException { final String collectionResult = KiotaJsonSerialization.serializeAsString( - true, - new ArrayList<>(Arrays.asList(entity))); + true, new ArrayList<>(Arrays.asList(entity))); assertEquals("[{}]", collectionResult); } @@ -164,12 +162,16 @@ void cleansContentType() throws IOException { entity.setId("123"); entity.setOfficeLocation("Nairobi"); - final String result = KiotaSerialization.serializeAsString("application/json;odata.metadata=minimal", entity); + final String result = + KiotaSerialization.serializeAsString( + "application/json;odata.metadata=minimal", entity); assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", result); - // Because onAfterObjectSerialization, returnOnlyChangedValues is set to false & initialization is completed + // Because onAfterObjectSerialization, returnOnlyChangedValues is set to false & + // initialization is completed entity.getBackingStore().setIsInitializationCompleted(false); - final String otherResult = KiotaSerialization.serializeAsString("application/vnd.github.raw+json", entity); + final String otherResult = + KiotaSerialization.serializeAsString("application/vnd.github.raw+json", entity); assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", otherResult); } } From 4837b520c4b741b06f392949c913da6b19dee459 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Fri, 4 Oct 2024 18:06:47 +0300 Subject: [PATCH 08/12] Fix sonarcloud issues --- .../mocks/TestBackedModelEntity.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java index a993a701a..cadacf5b0 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/mocks/TestBackedModelEntity.java @@ -30,16 +30,16 @@ public String getId() { return this.backingStore.get("id"); } - public void setId(String _id) { - this.backingStore.set("id", _id); + public void setId(String id) { + this.backingStore.set("id", id); } public String getOfficeLocation() { return this.backingStore.get("officeLocation"); } - public void setOfficeLocation(String _officeLocation) { - this.backingStore.set("officeLocation", _officeLocation); + public void setOfficeLocation(String officeLocation) { + this.backingStore.set("officeLocation", officeLocation); } public LocalDate getBirthDay() { @@ -88,37 +88,37 @@ public Map> getFieldDeserializers() { { put( "id", - (n) -> { + n -> { setId(n.getStringValue()); }); put( "officeLocation", - (n) -> { + n -> { setOfficeLocation(n.getStringValue()); }); put( "birthDay", - (n) -> { + n -> { setBirthDay(n.getLocalDateValue()); }); put( "workDuration", - (n) -> { + n -> { setWorkDuration(n.getPeriodAndDurationValue()); }); put( "startWorkTime", - (n) -> { + n -> { setStartWorkTime(n.getLocalTimeValue()); }); put( "endWorkTime", - (n) -> { + n -> { setEndWorkTime(n.getLocalTimeValue()); }); put( "createdDateTime", - (n) -> { + n -> { setCreatedDateTime(n.getOffsetDateTimeValue()); }); } From d5dc8f94a6621e99989f106af1a5eb4f695dc3de Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Mon, 7 Oct 2024 23:42:38 +0300 Subject: [PATCH 09/12] Refactor to add the boolean parameter at the end --- .../serialization/KiotaJsonSerialization.java | 16 +++++------ .../serialization/KiotaSerialization.java | 28 +++++++++---------- .../SerializationHelpersTest.java | 8 +++--- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java index 87eb2e836..ddf229f88 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaJsonSerialization.java @@ -35,9 +35,9 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { + @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { return KiotaSerialization.serializeAsStream( - CONTENT_TYPE, serializeOnlyChangedValues, value); + CONTENT_TYPE, value, serializeOnlyChangedValues); } /** @@ -61,9 +61,9 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - final boolean serializeOnlyChangedValues, @Nonnull final T value) throws IOException { + @Nonnull final T value, final boolean serializeOnlyChangedValues) throws IOException { return KiotaSerialization.serializeAsString( - CONTENT_TYPE, serializeOnlyChangedValues, value); + CONTENT_TYPE, value, serializeOnlyChangedValues); } /** @@ -87,10 +87,10 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static InputStream serializeAsStream( - final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) + @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) throws IOException { return KiotaSerialization.serializeAsStream( - CONTENT_TYPE, serializeOnlyChangedValues, values); + CONTENT_TYPE, values, serializeOnlyChangedValues); } /** @@ -114,10 +114,10 @@ private KiotaJsonSerialization() {} * @throws IOException when the stream cannot be closed or read. */ @Nonnull public static String serializeAsString( - final boolean serializeOnlyChangedValues, @Nonnull final Iterable values) + @Nonnull final Iterable values, final boolean serializeOnlyChangedValues) throws IOException { return KiotaSerialization.serializeAsString( - CONTENT_TYPE, serializeOnlyChangedValues, values); + CONTENT_TYPE, values, serializeOnlyChangedValues); } /** diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java index 11bb9ec90..a9c0a9e0e 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/KiotaSerialization.java @@ -30,7 +30,7 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, @Nonnull final T value) throws IOException { - return serializeAsStream(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, value); + return serializeAsStream(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); } /** @@ -44,8 +44,8 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, - final boolean serializeOnlyChangedValues, - @Nonnull final T value) + @Nonnull final T value, + final boolean serializeOnlyChangedValues) throws IOException { Objects.requireNonNull(value); try (final SerializationWriter writer = @@ -66,7 +66,7 @@ private KiotaSerialization() {} @Nonnull public static String serializeAsString( @Nonnull final String contentType, @Nonnull final T value) throws IOException { Objects.requireNonNull(value); - return serializeAsString(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, value); + return serializeAsString(contentType, value, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); } /** @@ -80,12 +80,12 @@ private KiotaSerialization() {} */ @Nonnull public static String serializeAsString( @Nonnull final String contentType, - final boolean serializeOnlyChangedValues, - @Nonnull final T value) + @Nonnull final T value, + final boolean serializeOnlyChangedValues) throws IOException { Objects.requireNonNull(value); try (final InputStream stream = - serializeAsStream(contentType, serializeOnlyChangedValues, value)) { + serializeAsStream(contentType, value, serializeOnlyChangedValues)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } @@ -102,7 +102,7 @@ private KiotaSerialization() {} @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); - return serializeAsStream(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, values); + return serializeAsStream(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); } /** @@ -116,8 +116,8 @@ private KiotaSerialization() {} */ @Nonnull public static InputStream serializeAsStream( @Nonnull final String contentType, - final boolean serializeOnlyChangedValues, - @Nonnull final Iterable values) + @Nonnull final Iterable values, + final boolean serializeOnlyChangedValues) throws IOException { Objects.requireNonNull(values); try (final SerializationWriter writer = @@ -139,7 +139,7 @@ private KiotaSerialization() {} @Nonnull final String contentType, @Nonnull final Iterable values) throws IOException { Objects.requireNonNull(values); - return serializeAsString(contentType, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES, values); + return serializeAsString(contentType, values, DEFAULT_SERIALIZE_ONLY_CHANGED_VALUES); } /** @@ -153,12 +153,12 @@ private KiotaSerialization() {} */ @Nonnull public static String serializeAsString( @Nonnull final String contentType, - final boolean serializeOnlyChangedValues, - @Nonnull final Iterable values) + @Nonnull final Iterable values, + final boolean serializeOnlyChangedValues) throws IOException { Objects.requireNonNull(values); try (final InputStream stream = - serializeAsStream(contentType, serializeOnlyChangedValues, values)) { + serializeAsStream(contentType, values, serializeOnlyChangedValues)) { return new String(Compatibility.readAllBytes(stream), CHARSET_NAME); } } diff --git a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java index 49add4c63..320050a7c 100644 --- a/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java +++ b/components/abstractions/src/test/java/com/microsoft/kiota/serialization/SerializationHelpersTest.java @@ -112,14 +112,14 @@ void serializesAllValuesInBackedModel() throws IOException { // Sets the backing store to be initialized. No properties are dirty entity.getBackingStore().setIsInitializationCompleted(true); - final String result = KiotaJsonSerialization.serializeAsString(false, entity); + final String result = KiotaJsonSerialization.serializeAsString(entity, false); assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); assertEquals("{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}", result); final String collectionResult = KiotaJsonSerialization.serializeAsString( - false, new ArrayList<>(Arrays.asList(entity))); + new ArrayList<>(Arrays.asList(entity)), false); assertEquals("[{\"id\":\"123\",\"officeLocation\":\"Nairobi\"}]", collectionResult); } @@ -138,14 +138,14 @@ void serializesChangedValuesInBackedModel() throws IOException { entity.setOfficeLocation("Nairobi"); entity.getBackingStore().setIsInitializationCompleted(true); - final String result = KiotaJsonSerialization.serializeAsString(true, entity); + final String result = KiotaJsonSerialization.serializeAsString(entity, true); assertFalse(entity.getBackingStore().getReturnOnlyChangedValues()); assertEquals("{}", result); final String collectionResult = KiotaJsonSerialization.serializeAsString( - true, new ArrayList<>(Arrays.asList(entity))); + new ArrayList<>(Arrays.asList(entity)), true); assertEquals("[{}]", collectionResult); } From 5922c544b92b999a33ce4e5e4b781d1a443ed457 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 8 Oct 2024 00:10:43 +0300 Subject: [PATCH 10/12] Add android lint disable option --- components/abstractions/android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/components/abstractions/android/build.gradle b/components/abstractions/android/build.gradle index 818e02384..63ed0cd21 100644 --- a/components/abstractions/android/build.gradle +++ b/components/abstractions/android/build.gradle @@ -57,6 +57,7 @@ android { disable "GradleDependency" disable "NewerVersionAvailable" disable "DuplicatePlatformClasses" // xpp3 added by azure-identity + disable "LambdaLast" // Wrongly enforced in KiotaJsonSerialization helpers } sourceSets { main { From 81d3b24b9620f567682a896c3464a8c242151199 Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 8 Oct 2024 00:11:18 +0300 Subject: [PATCH 11/12] Rename protected variable --- .../serialization/SerializationWriterProxyFactory.java | 8 ++++---- .../BackingStoreSerializationWriterProxyFactory.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java index 46d556f8b..fe3d34c99 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterProxyFactory.java @@ -10,10 +10,10 @@ /** Proxy factory that allows the composition of before and after callbacks on existing factories. */ public abstract class SerializationWriterProxyFactory implements SerializationWriterFactory { @Nonnull public String getValidContentType() { - return _concrete.getValidContentType(); + return proxiedFactory.getValidContentType(); } - protected final SerializationWriterFactory _concrete; + protected final SerializationWriterFactory proxiedFactory; private final Consumer _onBefore; private final Consumer _onAfter; private final BiConsumer _onStart; @@ -30,14 +30,14 @@ public SerializationWriterProxyFactory( @Nullable final Consumer onBeforeSerialization, @Nullable final Consumer onAfterSerialization, @Nullable final BiConsumer onStartObjectSerialization) { - _concrete = Objects.requireNonNull(concrete); + proxiedFactory = Objects.requireNonNull(concrete); _onBefore = onBeforeSerialization; _onAfter = onAfterSerialization; _onStart = onStartObjectSerialization; } @Nonnull public SerializationWriter getSerializationWriter(@Nonnull final String contentType) { - final SerializationWriter writer = _concrete.getSerializationWriter(contentType); + final SerializationWriter writer = proxiedFactory.getSerializationWriter(contentType); final Consumer originalBefore = writer.getOnBeforeObjectSerialization(); final Consumer originalAfter = writer.getOnAfterObjectSerialization(); final BiConsumer originalStart = diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java index f8c763123..b3d0d1fd1 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/store/BackingStoreSerializationWriterProxyFactory.java @@ -62,7 +62,7 @@ public BackingStoreSerializationWriterProxyFactory( @Nonnull public SerializationWriter getSerializationWriter( @Nonnull final String contentType, final boolean serializeOnlyChangedValues) { if (!serializeOnlyChangedValues) { - return _concrete.getSerializationWriter(contentType); + return proxiedFactory.getSerializationWriter(contentType); } return getSerializationWriter(contentType); } From 6a8b996e1d47be883cad7a36141587aa2224784d Mon Sep 17 00:00:00 2001 From: Philip Gichuhi Date: Tue, 8 Oct 2024 00:54:48 +0300 Subject: [PATCH 12/12] Refactor getting serialization writer in registry --- .../SerializationWriterFactoryRegistry.java | 78 +++++++------------ 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java index 23f82768b..9fcb2cb23 100644 --- a/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java +++ b/components/abstractions/src/main/java/com/microsoft/kiota/serialization/SerializationWriterFactoryRegistry.java @@ -3,6 +3,7 @@ import com.microsoft.kiota.store.BackingStoreSerializationWriterProxyFactory; import jakarta.annotation.Nonnull; +import jakarta.annotation.Nullable; import java.util.HashMap; import java.util.Objects; @@ -34,15 +35,7 @@ public SerializationWriterFactoryRegistry() { @Override @Nonnull public SerializationWriter getSerializationWriter(@Nonnull final String contentType) { - Objects.requireNonNull(contentType, "parameter contentType cannot be null"); - if (contentType.isEmpty()) { - throw new NullPointerException("contentType cannot be empty"); - } - final ContentTypeWrapper contentTypeWrapper = new ContentTypeWrapper(contentType); - final SerializationWriterFactory serializationWriterFactory = - getSerializationWriterFactory(contentTypeWrapper); - return serializationWriterFactory.getSerializationWriter( - contentTypeWrapper.cleanedContentType); + return getSerializationWriter(contentType, true); } /** @@ -50,46 +43,48 @@ public SerializationWriterFactoryRegistry() { * @param contentType * @param serializeOnlyChangedValues control backing store functionality * @return the serialization writer + * @throws RuntimeException when no factory is found for content type */ @Nonnull public SerializationWriter getSerializationWriter( @Nonnull final String contentType, final boolean serializeOnlyChangedValues) { + Objects.requireNonNull(contentType, "parameter contentType cannot be null"); + if (contentType.isEmpty()) { + throw new NullPointerException("contentType cannot be empty"); + } + String cleanedContentType = getVendorSpecificContentType(contentType); + SerializationWriterFactory factory = getSerializationWriterFactory(cleanedContentType); + if (factory == null) { + cleanedContentType = getCleanedVendorSpecificContentType(cleanedContentType); + factory = + getSerializationWriterFactory( + getCleanedVendorSpecificContentType(cleanedContentType)); + if (factory == null) { + throw new RuntimeException( + "Content type " + + contentType + + " does not have a factory to be serialized"); + } + } if (!serializeOnlyChangedValues) { - final ContentTypeWrapper contentTypeWrapper = new ContentTypeWrapper(contentType); - final SerializationWriterFactory factory = - getSerializationWriterFactory(contentTypeWrapper); if (factory instanceof BackingStoreSerializationWriterProxyFactory) { return ((BackingStoreSerializationWriterProxyFactory) factory) - .getSerializationWriter( - contentTypeWrapper.cleanedContentType, serializeOnlyChangedValues); + .getSerializationWriter(cleanedContentType, serializeOnlyChangedValues); } } - return getSerializationWriter(contentType); + return factory.getSerializationWriter(cleanedContentType); } /** * Gets a SerializationWriterFactory that is mapped to a cleaned content type string - * @param contentTypeWrapper wrapper object carrying initial content type and result of parsing it - * @return the serialization writer factory - * @throws RuntimeException when no mapped factory is found + * @param contentType wrapper object carrying initial content type and result of parsing it + * @return the serialization writer factory or null if no mapped factory is found */ - @Nonnull private SerializationWriterFactory getSerializationWriterFactory( - @Nonnull final ContentTypeWrapper contentTypeWrapper) { - final String vendorSpecificContentType = - getVendorSpecificContentType(contentTypeWrapper.contentType); - if (contentTypeAssociatedFactories.containsKey(vendorSpecificContentType)) { - contentTypeWrapper.cleanedContentType = vendorSpecificContentType; - return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); - } - final String cleanedContentType = - getCleanedVendorSpecificContentType(vendorSpecificContentType); - if (contentTypeAssociatedFactories.containsKey(cleanedContentType)) { - contentTypeWrapper.cleanedContentType = cleanedContentType; - return contentTypeAssociatedFactories.get(contentTypeWrapper.cleanedContentType); + @Nullable private SerializationWriterFactory getSerializationWriterFactory( + @Nonnull final String contentType) { + if (contentTypeAssociatedFactories.containsKey(contentType)) { + return contentTypeAssociatedFactories.get(contentType); } - throw new RuntimeException( - "Content type " - + contentTypeWrapper.contentType - + " does not have a factory to be serialized"); + return null; } /** @@ -113,17 +108,4 @@ public SerializationWriterFactoryRegistry() { @Nonnull private String getCleanedVendorSpecificContentType(@Nonnull final String contentType) { return contentTypeVendorCleanupPattern.matcher(contentType).replaceAll(""); } - - /** - * Wrapper class to carry the cleaned version of content-type after parsing in multiple stages - */ - private static final class ContentTypeWrapper { - String contentType; - String cleanedContentType; - - ContentTypeWrapper(@Nonnull final String contentType) { - this.contentType = contentType; - this.cleanedContentType = ""; - } - } }