FINERACT-2214: Remove pretty print parameter from api and serialization;

This commit is contained in:
viktorpavlenko
2025-03-19 12:23:29 +01:00
committed by Adam Saghy
parent 34cdf4d01f
commit a0ffaa1c0b
14 changed files with 37 additions and 191 deletions
@@ -79,15 +79,6 @@ public final class ApiParameterHelper {
}
}
public static boolean prettyPrint(final MultivaluedMap<String, String> queryParams) {
boolean prettyPrint = false;
if (queryParams.getFirst("pretty") != null) {
final String prettyPrintValue = queryParams.getFirst("pretty");
prettyPrint = "true".equalsIgnoreCase(prettyPrintValue);
}
return prettyPrint;
}
public static Locale extractLocale(final MultivaluedMap<String, String> queryParams) {
Locale locale = null;
if (queryParams.getFirst("locale") != null) {
@@ -38,27 +38,23 @@ public class ApiRequestParameterHelper {
public ApiRequestJsonSerializationSettings process(final MultivaluedMap<String, String> queryParameters,
final Set<String> mandatoryResponseParameters) {
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(queryParameters);
if (!responseParameters.isEmpty()) {
responseParameters.addAll(mandatoryResponseParameters);
}
final boolean prettyPrint = ApiParameterHelper.prettyPrint(queryParameters);
final boolean template = ApiParameterHelper.template(queryParameters);
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
return ApiRequestJsonSerializationSettings.from(prettyPrint, responseParameters, template, makerCheckerable, includeJson);
return ApiRequestJsonSerializationSettings.from(responseParameters, template, makerCheckerable, includeJson);
}
public ApiRequestJsonSerializationSettings process(final MultivaluedMap<String, String> queryParameters) {
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(queryParameters);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(queryParameters);
final boolean template = ApiParameterHelper.template(queryParameters);
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
return ApiRequestJsonSerializationSettings.from(prettyPrint, responseParameters, template, makerCheckerable, includeJson);
return ApiRequestJsonSerializationSettings.from(responseParameters, template, makerCheckerable, includeJson);
}
}
@@ -66,7 +66,7 @@ import org.springframework.stereotype.Component;
@AllArgsConstructor
public final class ErrorHandler {
private static final Gson JSON_HELPER = GoogleGsonSerializerHelper.createGsonBuilder(true).create();
private static final Gson JSON_HELPER = GoogleGsonSerializerHelper.createGsonBuilder().create();
private enum PessimisticLockingFailureCode {
@@ -19,55 +19,29 @@
package org.apache.fineract.infrastructure.core.serialization;
import java.util.Set;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* A class to encapsulate settings we allow on API that affect how JSON is to be serialized for the response to api
* call.
*/
@Getter
@RequiredArgsConstructor
public class ApiRequestJsonSerializationSettings {
private final boolean prettyPrint;
private final Set<String> parametersForPartialResponse;
private final boolean template;
private final boolean makerCheckerable;
private final boolean includeJson;
public ApiRequestJsonSerializationSettings(final boolean prettyPrint, final Set<String> parametersForPartialResponse,
final boolean template, final boolean makerCheckerable, final boolean includeJson) {
this.prettyPrint = prettyPrint;
this.parametersForPartialResponse = parametersForPartialResponse;
this.template = template;
this.makerCheckerable = makerCheckerable;
this.includeJson = includeJson;
}
public static ApiRequestJsonSerializationSettings from(final boolean prettyPrint, final Set<String> parametersForPartialResponse,
final boolean template, final boolean makerCheckerable, final boolean includeJson) {
public static ApiRequestJsonSerializationSettings from(final Set<String> parametersForPartialResponse, final boolean template,
final boolean makerCheckerable, final boolean includeJson) {
// FIXME - KW - rather than always creating new objects for this could
// just send by common ones like, prettyprint=false, empty response
// parameters
return new ApiRequestJsonSerializationSettings(prettyPrint, parametersForPartialResponse, template, makerCheckerable, includeJson);
}
public boolean isPrettyPrint() {
return this.prettyPrint;
}
public boolean isTemplate() {
return this.template;
}
public boolean isMakerCheckerable() {
return this.makerCheckerable;
}
public boolean isIncludeJson() {
return this.includeJson;
}
public Set<String> getParametersForPartialResponse() {
return this.parametersForPartialResponse;
return new ApiRequestJsonSerializationSettings(parametersForPartialResponse, template, makerCheckerable, includeJson);
}
public boolean isPartialResponseRequired() {
@@ -33,16 +33,13 @@ import org.springframework.stereotype.Component;
public class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<T> {
private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOff;
private final ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOn;
private final CommandProcessingResultJsonSerializer commandProcessingResultSerializer;
private final GoogleGsonSerializerHelper helper;
@Autowired
public DefaultToApiJsonSerializer(final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOff,
final ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOn,
final CommandProcessingResultJsonSerializer commandProcessingResultSerializer, final GoogleGsonSerializerHelper helper) {
this.excludeNothingWithPrettyPrintingOff = excludeNothingWithPrettyPrintingOff;
this.excludeNothingWithPrettyPrintingOn = excludeNothingWithPrettyPrintingOn;
this.commandProcessingResultSerializer = commandProcessingResultSerializer;
this.helper = helper;
}
@@ -57,18 +54,6 @@ public class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<T> {
return this.excludeNothingWithPrettyPrintingOff.serialize(object);
}
@Override
public String serializePretty(final boolean prettyOn, final Object object) {
String json = "";
if (prettyOn) {
json = this.excludeNothingWithPrettyPrintingOn.serialize(object);
} else {
json = serialize(object);
}
return json;
}
@Override
public String serialize(final ApiRequestJsonSerializationSettings settings, final Collection<T> collection,
final Set<String> supportedResponseParameters) {
@@ -109,49 +94,23 @@ public class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<T> {
}
private String serializeWithSettings(final Gson gson, final ApiRequestJsonSerializationSettings settings, final Object[] dataObject) {
String json = null;
if (gson != null) {
json = this.helper.serializedJsonFrom(gson, dataObject);
} else {
if (settings.isPrettyPrint()) {
json = this.excludeNothingWithPrettyPrintingOn.serialize(dataObject);
} else {
json = serialize(dataObject);
}
}
return json;
return gson != null ? this.helper.serializedJsonFrom(gson, dataObject) : serialize(dataObject);
}
private String serializeWithSettings(final Gson gson, final ApiRequestJsonSerializationSettings settings, final Object dataObject) {
String json = null;
if (gson != null) {
json = this.helper.serializedJsonFrom(gson, dataObject);
} else {
if (settings.isPrettyPrint()) {
json = this.excludeNothingWithPrettyPrintingOn.serialize(dataObject);
} else {
json = serialize(dataObject);
}
}
return json;
return gson != null ? this.helper.serializedJsonFrom(gson, dataObject) : serialize(dataObject);
}
private Gson findAppropriateSerializer(final ApiRequestJsonSerializationSettings settings,
final Set<String> supportedResponseParameters) {
Gson gson = null;
if (settings.isPartialResponseRequired()) {
gson = this.helper.createGsonBuilderWithParameterExclusionSerializationStrategy(supportedResponseParameters,
settings.isPrettyPrint(), settings.getParametersForPartialResponse());
}
return gson;
return settings.isPartialResponseRequired() ? this.helper.createGsonBuilderWithParameterExclusionSerializationStrategy(
supportedResponseParameters, settings.getParametersForPartialResponse()) : null;
}
private Gson findAppropriateSerializer(final ApiRequestJsonSerializationSettings settings) {
Gson gson = null;
if (settings.isPartialResponseRequired()) {
gson = this.helper.createGsonBuilderForPartialResponseFiltering(settings.isPrettyPrint(),
settings.getParametersForPartialResponse());
}
return gson;
return settings.isPartialResponseRequired()
? helper.createGsonBuilderForPartialResponseFiltering(settings.getParametersForPartialResponse())
: null;
}
}
@@ -1,46 +0,0 @@
/**
* 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.serialization;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.springframework.stereotype.Component;
/**
* A Google GSON implementation of contract.
*
* It serializes all fields of any Java {@link Object} passed to it.
*/
@Component
public final class ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson {
private final Gson gson;
public ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson() {
final GsonBuilder builder = new GsonBuilder();
GoogleGsonSerializerHelper.registerTypeAdapters(builder);
builder.setPrettyPrinting();
this.gson = builder.create();
}
public String serialize(final Object result) {
return this.gson.toJson(result);
}
}
@@ -50,19 +50,16 @@ import org.springframework.stereotype.Service;
@Service
public final class GoogleGsonSerializerHelper {
public Gson createGsonBuilderForPartialResponseFiltering(final boolean prettyPrint, final Set<String> responseParameters) {
public Gson createGsonBuilderForPartialResponseFiltering(final Set<String> responseParameters) {
final ExclusionStrategy strategy = new ParameterListInclusionStrategy(responseParameters);
final GsonBuilder builder = new GsonBuilder().addSerializationExclusionStrategy(strategy);
registerTypeAdapters(builder);
if (prettyPrint) {
builder.setPrettyPrinting();
}
return builder.create();
}
public Gson createGsonBuilderWithParameterExclusionSerializationStrategy(final Set<String> supportedParameters,
final boolean prettyPrint, final Set<String> responseParameters) {
final Set<String> responseParameters) {
final Set<String> parameterNamesToSkip = new HashSet<>();
@@ -84,9 +81,6 @@ public final class GoogleGsonSerializerHelper {
final GsonBuilder builder = new GsonBuilder().addSerializationExclusionStrategy(strategy);
registerTypeAdapters(builder);
if (prettyPrint) {
builder.setPrettyPrinting();
}
return builder.create();
}
@@ -103,15 +97,8 @@ public final class GoogleGsonSerializerHelper {
}
public static GsonBuilder createGsonBuilder() {
return createGsonBuilder(false);
}
public static GsonBuilder createGsonBuilder(final boolean prettyPrint) {
final GsonBuilder builder = new GsonBuilder();
registerTypeAdapters(builder);
if (prettyPrint) {
builder.setPrettyPrinting();
}
return builder;
}
@@ -26,8 +26,6 @@ public interface ToApiJsonSerializer<T> {
String serialize(Object object);
String serializePretty(boolean prettyOn, Object object);
String serializeResult(Object object);
String serialize(ApiRequestJsonSerializationSettings settings, Collection<T> collection);
@@ -77,7 +77,7 @@ class ErrorHandlerTest {
// then
Assertions.assertEquals(1234, errorInfo.getErrorCode());
Assertions.assertEquals("{\n \"Exception\": \"message body\"\n}", errorInfo.getMessage());
Assertions.assertEquals("{\"Exception\":\"message body\"}", errorInfo.getMessage());
Assertions.assertEquals(406, errorInfo.getStatusCode());
Mockito.verifyNoMoreInteractions(exceptionMapper);
Mockito.verifyNoInteractions(defaultExceptionMapper);
@@ -104,7 +104,7 @@ class ErrorHandlerTest {
// then
Assertions.assertEquals(1234, errorInfo.getErrorCode());
Assertions.assertEquals("{\n \"Exception\": \"message body\"\n}", errorInfo.getMessage());
Assertions.assertEquals("{\"Exception\":\"message body\"}", errorInfo.getMessage());
Assertions.assertEquals(406, errorInfo.getStatusCode());
Mockito.verifyNoMoreInteractions(inputMismatchMapper);
Mockito.verifyNoInteractions(exceptionMapper);
@@ -129,7 +129,7 @@ class ErrorHandlerTest {
// then
Assertions.assertEquals(1234, errorInfo.getErrorCode());
Assertions.assertEquals("{\n \"Exception\": \"message body\"\n}", errorInfo.getMessage());
Assertions.assertEquals("{\"Exception\":\"message body\"}", errorInfo.getMessage());
Assertions.assertEquals(406, errorInfo.getStatusCode());
Mockito.verifyNoInteractions(exceptionMapper);
Mockito.verifyNoMoreInteractions(defaultExceptionMapper);
@@ -89,8 +89,7 @@ public class DatatablesApiResource {
final List<DatatableData> result = this.readWriteNonCoreDataService.retrieveDatatableNames(apptable);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -201,9 +200,7 @@ public class DatatablesApiResource {
@Context final UriInfo uriInfo) {
final DatatableData result = this.readWriteNonCoreDataService.retrieveDatatable(datatable);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@@ -222,7 +219,7 @@ public class DatatablesApiResource {
final List<JsonObject> result = this.readWriteNonCoreDataService.queryDataTable(datatable, columnFilter, valueFilter,
resultColumns);
return this.toApiJsonSerializer.serializePretty(ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()), result);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -235,7 +232,7 @@ public class DatatablesApiResource {
public String advancedQuery(@PathParam("datatable") @Parameter(description = "datatable") final String datatable,
PagedLocalRequest<AdvancedQueryData> queryRequest, @Context final UriInfo uriInfo) {
final Page<JsonObject> result = this.readWriteNonCoreDataService.queryDataTableAdvanced(datatable, queryRequest);
return this.toApiJsonSerializer.serializePretty(ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()), result);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@@ -263,8 +260,8 @@ public class DatatablesApiResource {
String json = "";
final boolean genericResultSet = ApiParameterHelper.genericResultSet(uriInfo.getQueryParameters());
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint, results);
json = toApiJsonSerializer.serialize(results);
} else {
json = this.genericDataService.generateJsonFromGenericResultsetData(results);
}
@@ -288,8 +285,7 @@ public class DatatablesApiResource {
String json = "";
if (genericResultSet) {
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
json = this.toApiJsonSerializer.serializePretty(prettyPrint, results);
json = toApiJsonSerializer.serialize(results);
} else {
json = this.genericDataService.generateJsonFromGenericResultsetData(results);
}
@@ -42,7 +42,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.service.Page;
@@ -81,8 +80,7 @@ public class EntityDatatableChecksApiResource {
final Page<EntityDataTableChecksData> result = this.readEntityDatatableChecksService.retrieveAll(searchParameters, status, entity,
productId);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
return this.toApiJsonSerializer.serialize(result);
}
@GET
@@ -97,8 +95,7 @@ public class EntityDatatableChecksApiResource {
final EntityDataTableChecksTemplateData result = this.readEntityDatatableChecksService.retrieveTemplate();
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serializePretty(prettyPrint, result);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -46,19 +46,17 @@ public class JsonDatatableReportExportService implements DatatableReportExportSe
final GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(reportName, parameterTypeValue,
reportParams, isSelfServiceUserReport);
DatatableExportTargetParameter exportMode = DatatableExportTargetParameter.resolverExportTarget(queryParams);
boolean prettyPrint = exportMode == DatatableExportTargetParameter.PRETTY_JSON;
String json;
final boolean genericResultSetIsPassed = ApiParameterHelper.genericResultSetPassed(queryParams);
final boolean genericResultSet = ApiParameterHelper.genericResultSet(queryParams);
if (genericResultSetIsPassed) {
if (genericResultSet) {
json = this.toApiJsonSerializer.serializePretty(prettyPrint, result);
json = this.toApiJsonSerializer.serialize(result);
} else {
json = this.genericDataService.generateJsonFromGenericResultsetData(result);
}
} else {
json = this.toApiJsonSerializer.serializePretty(prettyPrint, result);
json = this.toApiJsonSerializer.serialize(result);
}
return new ResponseHolder(Response.Status.OK).entity(json).contentType(MediaType.APPLICATION_JSON);
@@ -47,7 +47,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.api.ApiParameterHelper;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
@@ -171,7 +170,7 @@ public class SavingsAccountTransactionsApiResource {
public String advancedQuery(@PathParam("savingsId") @Parameter(description = "savingsId") final Long savingsId,
PagedLocalRequest<AdvancedQueryRequest> queryRequest, @Context final UriInfo uriInfo) {
final Page<JsonObject> result = transactionsSearchService.queryAdvanced(savingsId, queryRequest);
return this.toApiJsonSerializer.serializePretty(ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()), result);
return this.toApiJsonSerializer.serialize(result);
}
@POST
@@ -26,7 +26,6 @@ import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.serialization.CommandProcessingResultJsonSerializer;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson;
import org.apache.fineract.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.junit.jupiter.api.Test;
@@ -35,8 +34,7 @@ public class BusinessDataSerialized {
@Test
public void serializeBusinessDateData() {
DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer = new DefaultToApiJsonSerializer<>(
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(),
new ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new GoogleGsonSerializerHelper());
LocalDate now = LocalDate.now(ZoneId.systemDefault());
@@ -49,8 +47,7 @@ public class BusinessDataSerialized {
@Test
public void serializeBusinessDateData_COB() {
DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer = new DefaultToApiJsonSerializer<>(
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(),
new ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new GoogleGsonSerializerHelper());
LocalDate now = LocalDate.now(ZoneId.systemDefault());