From 35339a6a8327a9f890f819aef1f7c3d106e15281 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Tue, 18 Mar 2025 22:23:44 +0100 Subject: [PATCH] FINERACT-2181: CommandProcessingResult serialization optimisation --- .../core/api/ExternalIdAdapter.java | 3 +- .../core/data/CommandProcessingResult.java | 12 ++-- .../JerseyJacksonObjectArgumentHandler.java | 18 ------ .../core/jersey/SimpleHttpOutputMessage.java | 42 ++++++++++++ ...mandProcessingResultSerializationTest.java | 64 +++++++++++++++++++ 5 files changed, 116 insertions(+), 23 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/SimpleHttpOutputMessage.java create mode 100644 fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/jersey/CommandProcessingResultSerializationTest.java diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ExternalIdAdapter.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ExternalIdAdapter.java index bde344d6d..7d46c9a3d 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ExternalIdAdapter.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/api/ExternalIdAdapter.java @@ -19,6 +19,7 @@ package org.apache.fineract.infrastructure.core.api; import com.google.gson.JsonElement; +import com.google.gson.JsonNull; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; @@ -35,7 +36,7 @@ public class ExternalIdAdapter implements JsonSerializer { @SuppressWarnings("unused") public JsonElement serialize(ExternalId src, Type typeOfSrc, JsonSerializationContext context) { if (src == null || src.isEmpty()) { - return null; + return JsonNull.INSTANCE; } return new JsonPrimitive(src.getValue()); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/CommandProcessingResult.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/CommandProcessingResult.java index 5b07f76bf..5ec8a948b 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/CommandProcessingResult.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/data/CommandProcessingResult.java @@ -31,7 +31,7 @@ import org.apache.fineract.infrastructure.core.domain.ExternalId; @Getter public class CommandProcessingResult implements Serializable { - private Long commandId; + private final Long commandId; private Long officeId; private final Long groupId; private final Long clientId; @@ -72,9 +72,9 @@ public class CommandProcessingResult implements Serializable { this.creditBureauReportData = creditBureauReportData; this.rollbackTransaction = rollbackTransaction; this.subResourceId = subResourceId; - this.resourceExternalId = resourceExternalId; - this.subResourceExternalId = subResourceExternalId; - this.loanExternalId = loanExternalId; + this.resourceExternalId = setExternalIdOrNull(resourceExternalId); + this.subResourceExternalId = setExternalIdOrNull(subResourceExternalId); + this.loanExternalId = setExternalIdOrNull(loanExternalId); } protected CommandProcessingResult(final Long resourceId, final Long officeId, final Long commandId, final Map changes, @@ -161,4 +161,8 @@ public class CommandProcessingResult implements Serializable { public void setRollbackTransaction(Boolean rollbackTransaction) { this.rollbackTransaction = rollbackTransaction; } + + private ExternalId setExternalIdOrNull(ExternalId externalId) { + return externalId == null || externalId.isEmpty() ? null : externalId; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyJacksonObjectArgumentHandler.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyJacksonObjectArgumentHandler.java index f0ce35890..d922789a6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyJacksonObjectArgumentHandler.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyJacksonObjectArgumentHandler.java @@ -37,7 +37,6 @@ import java.util.List; import lombok.RequiredArgsConstructor; import org.apache.commons.io.IOUtils; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.http.converter.json.MappingJacksonInputMessage; @@ -96,21 +95,4 @@ public class JerseyJacksonObjectArgumentHandler implements MessageBodyReader< converter.write(t, genericType, MediaType.APPLICATION_JSON, new SimpleHttpOutputMessage(entityStream, headers)); } } - - @RequiredArgsConstructor - private static final class SimpleHttpOutputMessage implements HttpOutputMessage { - - private final OutputStream outputStream; - private final HttpHeaders headers; - - @Override - public OutputStream getBody() throws IOException { - return outputStream; - } - - @Override - public HttpHeaders getHeaders() { - return headers; - } - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/SimpleHttpOutputMessage.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/SimpleHttpOutputMessage.java new file mode 100644 index 000000000..fe3b08c4c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/SimpleHttpOutputMessage.java @@ -0,0 +1,42 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.core.jersey; + +import java.io.IOException; +import java.io.OutputStream; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpOutputMessage; + +@RequiredArgsConstructor +public final class SimpleHttpOutputMessage implements HttpOutputMessage { + + private final OutputStream outputStream; + private final HttpHeaders headers; + + @Override + public OutputStream getBody() throws IOException { + return outputStream; + } + + @Override + public HttpHeaders getHeaders() { + return headers; + } +} diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/jersey/CommandProcessingResultSerializationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/jersey/CommandProcessingResultSerializationTest.java new file mode 100644 index 000000000..c279a2f30 --- /dev/null +++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/jersey/CommandProcessingResultSerializationTest.java @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.infrastructure.core.jersey; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.google.gson.Gson; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.Map; +import org.apache.fineract.TestConfiguration; +import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; +import org.apache.fineract.infrastructure.core.domain.ExternalId; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.test.context.ContextConfiguration; + +@SpringBootTest +@ContextConfiguration(classes = TestConfiguration.class) +public class CommandProcessingResultSerializationTest { + + @Autowired + private MappingJackson2HttpMessageConverter converter; + + @Test + public void testCommandProcessingResultSerialization() throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + CommandProcessingResult commandProcessingResult = CommandProcessingResult.fromDetails(1L, null, null, null, null, null, + "resourceIdentifier", null, null, null, null, null, null, null, Boolean.TRUE, null, new ExternalId("externalId"), + ExternalId.empty(), null); + SimpleHttpOutputMessage outputMessage = new SimpleHttpOutputMessage(os, headers); + converter.write(commandProcessingResult, MediaType.APPLICATION_JSON, outputMessage); + Map result = new Gson().fromJson(os.toString(Charset.defaultCharset()), Map.class); + assertEquals(4, result.size()); + assertEquals("resourceIdentifier", result.get("resourceIdentifier")); + assertEquals("externalId", result.get("resourceExternalId")); + assertEquals(1.0, result.get("commandId")); + assertEquals(true, result.get("rollbackTransaction")); + } + +}