From 170f22bcd244bd99f1ebd1e50c47b30595441eb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 23:08:54 +0000 Subject: [PATCH 01/12] chore: [DevOps] bump org.springframework:spring-framework-bom Bumps the production-major group with 1 update: [org.springframework:spring-framework-bom](https://github.com/spring-projects/spring-framework). Updates `org.springframework:spring-framework-bom` from 6.2.12 to 7.0.0 - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.2.12...v7.0.0) --- updated-dependencies: - dependency-name: org.springframework:spring-framework-bom dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: production-major ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f5b6d5f6a..932a608d1 100644 --- a/pom.xml +++ b/pom.xml @@ -98,7 +98,7 @@ - 6.2.12 + 7.0.0 6.1.5 2.0.17 3.27.6 From 0c5ee9051e3d4adde776dc7c9b1a44e0a1b164f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Tue, 18 Nov 2025 10:17:50 +0100 Subject: [PATCH 02/12] Remove Spring dependency from odata generators --- datamodel/odata-v4/odata-v4-generator/pom.xml | 4 --- .../generator/ODataToVdmGenerator.java | 17 +++++----- datamodel/odata/odata-generator/pom.xml | 4 --- .../odata/generator/ODataToVdmGenerator.java | 20 +++++------ .../generator/ODataToVdmGeneratorTest.java | 34 +++++++++++++++++++ 5 files changed, 53 insertions(+), 26 deletions(-) create mode 100644 datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java diff --git a/datamodel/odata-v4/odata-v4-generator/pom.xml b/datamodel/odata-v4/odata-v4-generator/pom.xml index 1beb671b4..ad9b88571 100644 --- a/datamodel/odata-v4/odata-v4-generator/pom.xml +++ b/datamodel/odata-v4/odata-v4-generator/pom.xml @@ -116,10 +116,6 @@ commons-io commons-io - - org.springframework - spring-core - com.sun.codemodel codemodel diff --git a/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java b/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java index 23e24cb5d..27c09c998 100644 --- a/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java +++ b/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java @@ -5,8 +5,11 @@ import java.io.InputStream; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -392,16 +395,14 @@ private String getCanonicalPath( @Nullable final File outputDir ) private boolean excludePatternMatch( final String excludeFilePattern, final String serviceMetadataFilename ) { final List excludeFilePatternEach = new ArrayList<>(Arrays.asList(excludeFilePattern.split(","))); - final AntPathMatcher antPathMatcher = new AntPathMatcher(); + final FileSystem fileSystem = FileSystems.getDefault(); for( final String filePattern : excludeFilePatternEach ) { - if( antPathMatcher.match(filePattern, serviceMetadataFilename) ) { - logger - .info( - String - .format( - "Excluding metadata file %s, as it matches with the excludes pattern.", - serviceMetadataFilename)); + final PathMatcher pathMatcher = fileSystem.getPathMatcher("glob:" + filePattern.trim()); + + if( pathMatcher.matches(Paths.get(serviceMetadataFilename)) ) { + final String msg = "Excluding metadata file %s, as it matches with the excludes pattern."; + logger.info(String.format(msg, serviceMetadataFilename)); return true; } } diff --git a/datamodel/odata/odata-generator/pom.xml b/datamodel/odata/odata-generator/pom.xml index 9f1f3bc21..2fa38a774 100644 --- a/datamodel/odata/odata-generator/pom.xml +++ b/datamodel/odata/odata-generator/pom.xml @@ -117,10 +117,6 @@ - - org.springframework - spring-core - com.sun.codemodel codemodel diff --git a/datamodel/odata/odata-generator/src/main/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGenerator.java b/datamodel/odata/odata-generator/src/main/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGenerator.java index 14fd167fd..151193b8b 100644 --- a/datamodel/odata/odata-generator/src/main/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGenerator.java +++ b/datamodel/odata/odata-generator/src/main/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGenerator.java @@ -6,8 +6,11 @@ import java.lang.reflect.Field; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; @@ -29,7 +32,6 @@ import org.apache.olingo.odata2.core.edm.provider.EdmImplProv; import org.apache.olingo.odata2.core.edm.provider.EdmxProvider; import org.slf4j.Logger; -import org.springframework.util.AntPathMatcher; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; @@ -349,19 +351,17 @@ private String getCanonicalPath( @Nullable final File outputDir ) } } - private boolean excludePatternMatch( final String excludeFilePattern, final String serviceMetadataFilename ) + static boolean excludePatternMatch( final String excludeFilePattern, final String serviceMetadataFilename ) { final List excludeFilePatternEach = new ArrayList<>(Arrays.asList(excludeFilePattern.split(","))); - final AntPathMatcher antPathMatcher = new AntPathMatcher(); + final FileSystem fileSystem = FileSystems.getDefault(); for( final String filePattern : excludeFilePatternEach ) { - if( antPathMatcher.match(filePattern, serviceMetadataFilename) ) { - logger - .info( - String - .format( - "Excluding metadata file %s, as it matches with the excludes pattern.", - serviceMetadataFilename)); + final PathMatcher pathMatcher = fileSystem.getPathMatcher("glob:" + filePattern.trim()); + + if( pathMatcher.matches(Paths.get(serviceMetadataFilename)) ) { + final String msg = "Excluding metadata file %s, as it matches with the excludes pattern."; + logger.info(String.format(msg, serviceMetadataFilename)); return true; } } diff --git a/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java b/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java new file mode 100644 index 000000000..646f0f611 --- /dev/null +++ b/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java @@ -0,0 +1,34 @@ +package com.sap.cloud.sdk.datamodel.odata.generator; + +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; + +import java.io.File; + +import static com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator.excludePatternMatch; + +public class ODataToVdmGeneratorTest +{ + @Test + void testExcludePatternMatch() + { + // Get file-name only, without path + final String fileName = new File("src/test/resources/sample/Spec.edmx").getName(); + + final SoftAssertions softly = new SoftAssertions(); + for( final String pattern : new String[] { "*.edmx", "*.*", "sp*c.edmx", "*.EDMX" } ) + softly + .assertThat(excludePatternMatch(pattern, fileName)) + .describedAs("%s matches %s", pattern, fileName) + .isTrue(); + + for( final String pattern : new String[] { "F", "*/*", "/resources/*/*.edmx", "/resources/*/*" } ) + softly + .assertThat(excludePatternMatch(pattern, fileName)) + .describedAs("%s not matches %s", pattern, fileName) + .isFalse(); + + softly.assertThat(excludePatternMatch("A,B,spec.edmx", fileName)).describedAs("fallback").isTrue(); + softly.assertAll(); + } +} From f11fa1a50a368461af11bdbfeddec21e840ff36e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Tue, 18 Nov 2025 10:18:59 +0100 Subject: [PATCH 03/12] Exclude banned dependency --- datamodel/openapi/openapi-api-sample/pom.xml | 6 ++++++ datamodel/openapi/openapi-core/pom.xml | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/datamodel/openapi/openapi-api-sample/pom.xml b/datamodel/openapi/openapi-api-sample/pom.xml index d373bb45e..292235843 100644 --- a/datamodel/openapi/openapi-api-sample/pom.xml +++ b/datamodel/openapi/openapi-api-sample/pom.xml @@ -54,6 +54,12 @@ org.springframework spring-core + + + commons-logging + commons-logging + + org.springframework diff --git a/datamodel/openapi/openapi-core/pom.xml b/datamodel/openapi/openapi-core/pom.xml index 44d87216d..cd710434a 100644 --- a/datamodel/openapi/openapi-core/pom.xml +++ b/datamodel/openapi/openapi-core/pom.xml @@ -59,6 +59,12 @@ org.springframework spring-core + + + commons-logging + commons-logging + + org.springframework From 7c9ae630efb9b319b902bf592f15335dfad7e105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Tue, 18 Nov 2025 10:27:20 +0100 Subject: [PATCH 04/12] impsort --- .../datamodel/odatav4/generator/ODataToVdmGenerator.java | 1 - .../datamodel/odata/generator/ODataToVdmGeneratorTest.java | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java b/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java index 27c09c998..65e234cb6 100644 --- a/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java +++ b/datamodel/odata-v4/odata-v4-generator/src/main/java/com/sap/cloud/sdk/datamodel/odatav4/generator/ODataToVdmGenerator.java @@ -36,7 +36,6 @@ import org.apache.olingo.commons.api.edm.provider.CsdlTerm; import org.apache.olingo.commons.api.format.ContentType; import org.slf4j.Logger; -import org.springframework.util.AntPathMatcher; import com.google.common.collect.Multimap; import com.sap.cloud.sdk.cloudplatform.util.StringUtils; diff --git a/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java b/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java index 646f0f611..ed508865c 100644 --- a/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java +++ b/datamodel/odata/odata-generator/src/test/java/com/sap/cloud/sdk/datamodel/odata/generator/ODataToVdmGeneratorTest.java @@ -1,11 +1,11 @@ package com.sap.cloud.sdk.datamodel.odata.generator; -import org.assertj.core.api.SoftAssertions; -import org.junit.jupiter.api.Test; +import static com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator.excludePatternMatch; import java.io.File; -import static com.sap.cloud.sdk.datamodel.odata.generator.ODataToVdmGenerator.excludePatternMatch; +import org.assertj.core.api.SoftAssertions; +import org.junit.jupiter.api.Test; public class ODataToVdmGeneratorTest { From e50bb921cff11427bc0b6937efa35a23891815fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 16:39:51 +0100 Subject: [PATCH 05/12] Add multi jackson support --- datamodel/openapi/openapi-core/pom.xml | 29 ++++++ .../services/openapi/apiclient/ApiClient.java | 64 ++++++------- .../openapi/apiclient/ConverterPatcher.java | 96 +++++++++++++++++++ .../openapi/core/OpenApiResponse.java | 4 +- .../openapi/apiclient/ApiClientTest.java | 24 +++++ .../ApiClientViaConstructorTest.java | 2 +- .../GenericParameterTest.java | 6 +- 7 files changed, 183 insertions(+), 42 deletions(-) create mode 100644 datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java create mode 100644 datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientTest.java diff --git a/datamodel/openapi/openapi-core/pom.xml b/datamodel/openapi/openapi-core/pom.xml index cd710434a..f9c1acca3 100644 --- a/datamodel/openapi/openapi-core/pom.xml +++ b/datamodel/openapi/openapi-core/pom.xml @@ -47,6 +47,7 @@ com.fasterxml.jackson.core jackson-databind + provided com.fasterxml.jackson.core @@ -55,7 +56,31 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 + provided + + org.slf4j + slf4j-api + provided + + + tools.jackson.core + jackson-core + 3.0.2 + true + + + tools.jackson.core + jackson-databind + 3.0.2 + true + + + org.skyscreamer + jsonassert + 1.5.3 + test + org.springframework spring-core @@ -116,6 +141,10 @@ com.fasterxml.jackson.core:jackson-core + + tools.jackson.core:jackson-core + org.skyscreamer:jsonassert + diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java index fd0851050..392cb72a5 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java @@ -9,6 +9,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -27,18 +28,13 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.client.BufferingClientHttpRequestFactory; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverter; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; -import com.fasterxml.jackson.annotation.JsonAutoDetect; -import com.fasterxml.jackson.annotation.PropertyAccessor; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.sap.cloud.sdk.cloudplatform.connectivity.ApacheHttpClient5Accessor; import com.sap.cloud.sdk.cloudplatform.connectivity.Destination; import com.sap.cloud.sdk.services.openapi.apiclient.auth.ApiKeyAuth; @@ -51,6 +47,8 @@ */ public final class ApiClient { + private static final ConverterPatcher[] CONVERTER_PATCHES = + { new ConverterPatcher.Jackson2(), new ConverterPatcher.Jackson3() }; /** * Enum representing the delimiter of a given collection. @@ -688,8 +686,7 @@ public T invokeAPI( // auth headers are added automatically by the SDK // updateParamsForAuth(authNames, queryParams, headerParams); - @SuppressWarnings( "deprecation" ) // spring-web:6.2.0 and later, works until <7.0.0 - final UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(basePath).path(path); + final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(basePath).path(path); if( queryParams != null ) { //encode the query parameters in case they contain unsafe characters for( final List values : queryParams.values() ) { @@ -724,7 +721,7 @@ public T invokeAPI( final ResponseEntity responseEntity = restTemplate.exchange(requestEntity, returnType); statusCode = responseEntity.getStatusCode().value(); - responseHeaders = responseEntity.getHeaders(); + responseHeaders = extractHeadersMap(responseEntity.getHeaders()); if( statusCode == 204 ) { return null; @@ -737,6 +734,22 @@ public T invokeAPI( } } + @SuppressWarnings( "unchecked" ) + static MultiValueMap extractHeadersMap( @Nonnull final HttpHeaders headers ) + { + if( headers instanceof MultiValueMap ) { + return (MultiValueMap) headers; // until including Spring Framework 6 + } + try { + return (MultiValueMap) HttpHeaders.class + .getDeclaredMethod("asMultiValueMap") // since Spring Framework 7 + .invoke(headers); + } + catch( final Exception e ) { + return MultiValueMap.fromSingleValue(headers.toSingleValueMap()); // fallback + } + } + /** * Add headers to the request that is being built * @@ -748,14 +761,7 @@ public T invokeAPI( private void addHeadersToRequest( @Nullable final HttpHeaders headers, final BodyBuilder requestBuilder ) { if( headers != null ) { - for( final Entry> entry : headers.entrySet() ) { - final List values = entry.getValue(); - for( final String value : values ) { - if( value != null ) { - requestBuilder.header(entry.getKey(), value); - } - } - } + requestBuilder.headers(headers); } } @@ -763,28 +769,14 @@ private void addHeadersToRequest( @Nullable final HttpHeaders headers, final Bod private static RestTemplate newDefaultRestTemplate() { final RestTemplate restTemplate = new RestTemplate(); - - final ObjectMapper objectMapper = newDefaultObjectMapper(); - restTemplate - .getMessageConverters() - .stream() - .filter(MappingJackson2HttpMessageConverter.class::isInstance) - .map(MappingJackson2HttpMessageConverter.class::cast) - .forEach(converter -> converter.setObjectMapper(objectMapper)); - + final List> converters = new LinkedList<>(restTemplate.getMessageConverters()); + for( final ConverterPatcher patcher : CONVERTER_PATCHES ) { + patcher.patchList(converters); + } + restTemplate.setMessageConverters(converters); return restTemplate; } - @Nonnull - private static ObjectMapper newDefaultObjectMapper() - { - return new Jackson2ObjectMapperBuilder() - .modules(new JavaTimeModule()) - .visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) - .visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE) - .build(); - } - @Nonnull private static RestTemplate diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java new file mode 100644 index 000000000..e3206b8e8 --- /dev/null +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -0,0 +1,96 @@ +package com.sap.cloud.sdk.services.openapi.apiclient; + +import java.util.List; +import java.util.ListIterator; +import java.util.function.UnaryOperator; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; + +import lombok.extern.slf4j.Slf4j; + +// DO NOT IMPORT JACKSON CLASSES OTHER THAN ANNOTATIONS + +@FunctionalInterface +interface ConverterPatcher +{ + @Nullable + T patch( @Nonnull T instance ); + + default void patchList( @Nonnull final List instances ) + { + final ListIterator iterator = instances.listIterator(); + while( iterator.hasNext() ) { + final T instance = patch(iterator.next()); + if( instance != null ) { + iterator.set(instance); + } else { + iterator.remove(); + } + } + } + + @Slf4j + class Jackson2 implements ConverterPatcher + { + @SuppressWarnings( "removal" ) + @Override + public T patch( @Nonnull final T instance ) + { + final String springJacksonConverter = + "org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"; + final Class cl = instance.getClass(); + if( cl.getName().equals(springJacksonConverter) ) { + try { + final com.fasterxml.jackson.databind.ObjectMapper mapper = + new org.springframework.http.converter.json.Jackson2ObjectMapperBuilder() + .modules(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()) + .visibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) + .visibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE) + .build(); + ((org.springframework.http.converter.json.MappingJackson2HttpMessageConverter) instance) + .setObjectMapper(mapper); + } + catch( final Exception e ) { + log.error("Failed to apply Jackson2 patch: " + e.getMessage(), e); + } + } + return instance; + } + } + + @Slf4j + class Jackson3 implements ConverterPatcher + { + @SuppressWarnings( "unchecked" ) + @Override + public T patch( @Nonnull final T instance ) + { + final String springJacksonConverter = + "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; + final Class cl = instance.getClass(); + if( cl.getName().equals(springJacksonConverter) ) { + final UnaryOperator vc = + v -> v + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + .withSetterVisibility(JsonAutoDetect.Visibility.NONE); + tools.jackson.databind.json.JsonMapper.Builder builder = + ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance).getMapper().rebuild(); + builder = builder.changeDefaultVisibility(vc); + try { + final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); + final tools.jackson.databind.ValueSerializer ser = new tools.jackson.databind.ser.jackson.RawSerializer<>(jackson2ser); + builder = builder.addModule(new tools.jackson.databind.module.SimpleModule().addSerializer(ser)); + } + catch( final ClassNotFoundException e ) { + log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); + } + return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); + } + return instance; + } + } +} diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiResponse.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiResponse.java index d0e4da65f..d6c6b6145 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiResponse.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/core/OpenApiResponse.java @@ -2,7 +2,7 @@ import javax.annotation.Nonnull; -import org.springframework.http.HttpHeaders; +import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import com.sap.cloud.sdk.services.openapi.apiclient.ApiClient; @@ -48,6 +48,6 @@ public OpenApiResponse( @Nonnull final ApiClient client ) public OpenApiResponse( final int statusCode ) { this.statusCode = statusCode; - headers = new HttpHeaders(); + headers = new LinkedMultiValueMap<>(); } } diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientTest.java new file mode 100644 index 000000000..650b804d8 --- /dev/null +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientTest.java @@ -0,0 +1,24 @@ +package com.sap.cloud.sdk.services.openapi.apiclient; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.http.HttpHeaders; + +public class ApiClientTest +{ + + @Test + void testExtractHeadersMap() + { + HttpHeaders headers = new HttpHeaders(); + headers.add("foo", "bar"); + headers.add("baz", "qux"); + headers.add("baz", "quux"); + assertThat(ApiClient.extractHeadersMap(headers)) + .containsExactly(entry("foo", List.of("bar")), entry("baz", List.of("qux", "quux"))); + } +} diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientViaConstructorTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientViaConstructorTest.java index b7cda71d3..5a724771b 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientViaConstructorTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClientViaConstructorTest.java @@ -64,7 +64,7 @@ void testApiClientDoesNotChangeTheGivenRestTemplate() server .expect(ExpectedCount.twice(), requestTo(BASE_PATH + RELATIVE_PATH)) .andExpect(method(HttpMethod.POST)) - .andExpect(content().string("{\"return\":\"Hello, World!\",\"Return\":\"Hello, World!\"}")) + .andExpect(content().json("{\"return\":\"Hello, World!\",\"Return\":\"Hello, World!\"}")) .andRespond(MockRestResponseCreators.withSuccess(SUCCESS_BODY, MediaType.TEXT_PLAIN)); // first service invocation diff --git a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java index f50df180f..b2143de13 100644 --- a/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java +++ b/datamodel/openapi/openapi-core/src/test/java/com/sap/cloud/sdk/services/openapi/genericparameter/GenericParameterTest.java @@ -1,7 +1,7 @@ package com.sap.cloud.sdk.services.openapi.genericparameter; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; @@ -57,7 +57,7 @@ void testInvocationWithGenericParameter( @Nonnull final WireMockRuntimeInfo wm ) WireMock .stubFor( post(urlEqualTo("/api")) - .withRequestBody(equalTo(expectedBody)) + .withRequestBody(equalToJson(expectedBody)) .willReturn(aResponse().withStatus(HttpStatus.SC_OK))); final DefaultHttpDestination httpDestination = DefaultHttpDestination.builder(wm.getHttpBaseUrl()).build(); @@ -76,7 +76,7 @@ void testInvocationWithGenericParameter( @Nonnull final WireMockRuntimeInfo wm ) .fieldPopulatedAsStringWithoutAnnotation(jsonString) .fieldPopulatedAsJacksonJsonNode(jacksonJsonNode) .build()); - verify(postRequestedFor(urlEqualTo("/api")).withRequestBody(equalTo(expectedBody))); + verify(postRequestedFor(urlEqualTo("/api")).withRequestBody(equalToJson(expectedBody))); } @Value From 426f35ce7a3b3e9ebd96c9a5577450e4d8fce295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 16:48:07 +0100 Subject: [PATCH 06/12] Format --- .../sdk/services/openapi/apiclient/ConverterPatcher.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java index e3206b8e8..eaab6f9a7 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -78,11 +78,14 @@ public T patch( @Nonnull final T instance ) .withGetterVisibility(JsonAutoDetect.Visibility.NONE) .withSetterVisibility(JsonAutoDetect.Visibility.NONE); tools.jackson.databind.json.JsonMapper.Builder builder = - ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance).getMapper().rebuild(); + ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance) + .getMapper() + .rebuild(); builder = builder.changeDefaultVisibility(vc); try { final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); - final tools.jackson.databind.ValueSerializer ser = new tools.jackson.databind.ser.jackson.RawSerializer<>(jackson2ser); + final tools.jackson.databind.ValueSerializer ser = + new tools.jackson.databind.ser.jackson.RawSerializer<>(jackson2ser); builder = builder.addModule(new tools.jackson.databind.module.SimpleModule().addSerializer(ser)); } catch( final ClassNotFoundException e ) { From 2560149367a410163416664320775188027822d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:11:50 +0100 Subject: [PATCH 07/12] Fix runtime class path when using Spring6+Jackson2 --- .../openapi/apiclient/ConverterPatcher.java | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java index eaab6f9a7..10c2e9092 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -1,5 +1,6 @@ package com.sap.cloud.sdk.services.openapi.apiclient; +import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.ListIterator; import java.util.function.UnaryOperator; @@ -69,31 +70,33 @@ class Jackson3 implements ConverterPatcher @Override public T patch( @Nonnull final T instance ) { - final String springJacksonConverter = - "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; - final Class cl = instance.getClass(); - if( cl.getName().equals(springJacksonConverter) ) { - final UnaryOperator vc = - v -> v - .withGetterVisibility(JsonAutoDetect.Visibility.NONE) - .withSetterVisibility(JsonAutoDetect.Visibility.NONE); - tools.jackson.databind.json.JsonMapper.Builder builder = - ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance) - .getMapper() - .rebuild(); - builder = builder.changeDefaultVisibility(vc); - try { - final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); - final tools.jackson.databind.ValueSerializer ser = - new tools.jackson.databind.ser.jackson.RawSerializer<>(jackson2ser); - builder = builder.addModule(new tools.jackson.databind.module.SimpleModule().addSerializer(ser)); - } - catch( final ClassNotFoundException e ) { - log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); - } - return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); + final String springJacksonConverter = + "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; + final Class cl = instance.getClass(); + if( cl.getName().equals(springJacksonConverter) ) { + final UnaryOperator vc = + v -> v + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + .withSetterVisibility(JsonAutoDetect.Visibility.NONE); + tools.jackson.databind.json.JsonMapper.Builder builder = + ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance) + .getMapper() + .rebuild(); + builder = builder.changeDefaultVisibility(vc); + try { + final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); + final Object serializer = Class.forName("tools.jackson.databind.ser.jackson.RawSerializer").getConstructor(Class.class).newInstance(jackson2ser); + Object module = Class.forName("tools.jackson.databind.module.SimpleModule").getConstructor().newInstance(); + module = module.getClass().getMethod("addSerializer", serializer.getClass()).invoke(module, serializer); + builder = (tools.jackson.databind.json.JsonMapper.Builder) builder.getClass().getMethod("addModule", module.getClass()).invoke(builder, module); } - return instance; + catch( final ClassNotFoundException | NoSuchMethodException | InstantiationException | + IllegalAccessException | InvocationTargetException e ) { + log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); + } + return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); + } + return instance; } } } From 783b10963b9e758110491054aed2288e3c9f270b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:12:32 +0100 Subject: [PATCH 08/12] Format --- .../openapi/apiclient/ConverterPatcher.java | 66 +++++++++++-------- 1 file changed, 40 insertions(+), 26 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java index 10c2e9092..65b5fe6e6 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -70,33 +70,47 @@ class Jackson3 implements ConverterPatcher @Override public T patch( @Nonnull final T instance ) { - final String springJacksonConverter = - "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; - final Class cl = instance.getClass(); - if( cl.getName().equals(springJacksonConverter) ) { - final UnaryOperator vc = - v -> v - .withGetterVisibility(JsonAutoDetect.Visibility.NONE) - .withSetterVisibility(JsonAutoDetect.Visibility.NONE); - tools.jackson.databind.json.JsonMapper.Builder builder = - ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance) - .getMapper() - .rebuild(); - builder = builder.changeDefaultVisibility(vc); - try { - final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); - final Object serializer = Class.forName("tools.jackson.databind.ser.jackson.RawSerializer").getConstructor(Class.class).newInstance(jackson2ser); - Object module = Class.forName("tools.jackson.databind.module.SimpleModule").getConstructor().newInstance(); - module = module.getClass().getMethod("addSerializer", serializer.getClass()).invoke(module, serializer); - builder = (tools.jackson.databind.json.JsonMapper.Builder) builder.getClass().getMethod("addModule", module.getClass()).invoke(builder, module); - } - catch( final ClassNotFoundException | NoSuchMethodException | InstantiationException | - IllegalAccessException | InvocationTargetException e ) { - log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); + final String springJacksonConverter = + "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; + final Class cl = instance.getClass(); + if( cl.getName().equals(springJacksonConverter) ) { + final UnaryOperator vc = + v -> v + .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + .withSetterVisibility(JsonAutoDetect.Visibility.NONE); + tools.jackson.databind.json.JsonMapper.Builder builder = + ((org.springframework.http.converter.json.JacksonJsonHttpMessageConverter) instance) + .getMapper() + .rebuild(); + builder = builder.changeDefaultVisibility(vc); + try { + final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); + final Object serializer = + Class + .forName("tools.jackson.databind.ser.jackson.RawSerializer") + .getConstructor(Class.class) + .newInstance(jackson2ser); + Object module = + Class.forName("tools.jackson.databind.module.SimpleModule").getConstructor().newInstance(); + module = + module.getClass().getMethod("addSerializer", serializer.getClass()).invoke(module, serializer); + builder = + (tools.jackson.databind.json.JsonMapper.Builder) builder + .getClass() + .getMethod("addModule", module.getClass()) + .invoke(builder, module); + } + catch( final + ClassNotFoundException + | NoSuchMethodException + | InstantiationException + | IllegalAccessException + | InvocationTargetException e ) { + log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); + } + return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); } - return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); - } - return instance; + return instance; } } } From acc3ae4158e3b93b4a56cee5682636cc41a515cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:13:26 +0100 Subject: [PATCH 09/12] Use HttpHeaders#set instead of #remove + #add because #remove requires Object in Spring6 and String in Spring7. In binary code this is incompatible! --- .../sap/cloud/sdk/services/openapi/apiclient/ApiClient.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java index 392cb72a5..92dec8792 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ApiClient.java @@ -336,8 +336,7 @@ public ApiClient setUserAgent( @Nonnull final String userAgent ) @Nonnull public ApiClient addDefaultHeader( @Nonnull final String name, @Nonnull final String value ) { - defaultHeaders.remove(name); - defaultHeaders.add(name, value); + defaultHeaders.set(name, value); return this; } From ff29c4f771ef090a2dba6b338ed1e67c1003ba6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:14:07 +0100 Subject: [PATCH 10/12] Have sample project use Spring6+Jackson2 (legacy) --- datamodel/openapi/openapi-api-sample/pom.xml | 20 ++++++++++++++------ pom.xml | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/datamodel/openapi/openapi-api-sample/pom.xml b/datamodel/openapi/openapi-api-sample/pom.xml index 292235843..732400ab7 100644 --- a/datamodel/openapi/openapi-api-sample/pom.xml +++ b/datamodel/openapi/openapi-api-sample/pom.xml @@ -28,6 +28,20 @@ https://www.sap.com + + + + org.springframework + spring-core + ${spring6.version} + + + org.springframework + spring-web + ${spring6.version} + + + com.sap.cloud.sdk.datamodel @@ -54,12 +68,6 @@ org.springframework spring-core - - - commons-logging - commons-logging - - org.springframework diff --git a/pom.xml b/pom.xml index 932a608d1..dd874f3d9 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,7 @@ 7.0.0 + 6.2.12 6.1.5 2.0.17 3.27.6 From cb74e29fde391e752be46ae2101ab2932a3623c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:19:08 +0100 Subject: [PATCH 11/12] Minor syntax --- .../openapi/apiclient/ConverterPatcher.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java index 65b5fe6e6..14399d55a 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -70,6 +70,14 @@ class Jackson3 implements ConverterPatcher @Override public T patch( @Nonnull final T instance ) { + // run the following code respectively if the classes were available: + + // Builder builder = ((JacksonJsonHttpMessageConverter) instance).getMapper().rebuild() + // .changeDefaultVisibility(v -> v + // .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + // .withSetterVisibility(JsonAutoDetect.Visibility.NONE)); + // return (T) new JacksonJsonHttpMessageConverter(builder); + final String springJacksonConverter = "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; final Class cl = instance.getClass(); @@ -84,14 +92,17 @@ public T patch( @Nonnull final T instance ) .rebuild(); builder = builder.changeDefaultVisibility(vc); try { - final Class jackson2ser = Class.forName("com.fasterxml.jackson.databind.JsonSerializable"); - final Object serializer = + final String jackson2SerName = "com.fasterxml.jackson.databind.JsonSerializable"; + final String serializerName = "tools.jackson.databind.ser.jackson.RawSerializer"; + final String moduleName = "tools.jackson.databind.module.SimpleModule"; + final Class jackson2ser = Class.forName(jackson2SerName); + final Object serializer = Class - .forName("tools.jackson.databind.ser.jackson.RawSerializer") + .forName(serializerName) .getConstructor(Class.class) .newInstance(jackson2ser); - Object module = - Class.forName("tools.jackson.databind.module.SimpleModule").getConstructor().newInstance(); + Object module = + Class.forName(moduleName).getConstructor().newInstance(); module = module.getClass().getMethod("addSerializer", serializer.getClass()).invoke(module, serializer); builder = @@ -101,11 +112,7 @@ public T patch( @Nonnull final T instance ) .invoke(builder, module); } catch( final - ClassNotFoundException - | NoSuchMethodException - | InstantiationException - | IllegalAccessException - | InvocationTargetException e ) { + Exception e ) { log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); } return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder); From ad3205b5121112584f0bb024edda9d326131fb84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=BCmont?= Date: Wed, 19 Nov 2025 17:20:38 +0100 Subject: [PATCH 12/12] Format --- .../openapi/apiclient/ConverterPatcher.java | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java index 14399d55a..2950637e6 100644 --- a/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java +++ b/datamodel/openapi/openapi-core/src/main/java/com/sap/cloud/sdk/services/openapi/apiclient/ConverterPatcher.java @@ -1,6 +1,5 @@ package com.sap.cloud.sdk.services.openapi.apiclient; -import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.ListIterator; import java.util.function.UnaryOperator; @@ -70,13 +69,13 @@ class Jackson3 implements ConverterPatcher @Override public T patch( @Nonnull final T instance ) { - // run the following code respectively if the classes were available: - - // Builder builder = ((JacksonJsonHttpMessageConverter) instance).getMapper().rebuild() - // .changeDefaultVisibility(v -> v - // .withGetterVisibility(JsonAutoDetect.Visibility.NONE) - // .withSetterVisibility(JsonAutoDetect.Visibility.NONE)); - // return (T) new JacksonJsonHttpMessageConverter(builder); + // run the following code respectively if the classes were available: + // + // Builder builder = ((JacksonJsonHttpMessageConverter) instance).getMapper().rebuild() + // .changeDefaultVisibility(v -> v + // .withGetterVisibility(JsonAutoDetect.Visibility.NONE) + // .withSetterVisibility(JsonAutoDetect.Visibility.NONE)); + // return (T) new JacksonJsonHttpMessageConverter(builder); final String springJacksonConverter = "org.springframework.http.converter.json.JacksonJsonHttpMessageConverter"; @@ -92,17 +91,13 @@ public T patch( @Nonnull final T instance ) .rebuild(); builder = builder.changeDefaultVisibility(vc); try { - final String jackson2SerName = "com.fasterxml.jackson.databind.JsonSerializable"; - final String serializerName = "tools.jackson.databind.ser.jackson.RawSerializer"; - final String moduleName = "tools.jackson.databind.module.SimpleModule"; - final Class jackson2ser = Class.forName(jackson2SerName); - final Object serializer = - Class - .forName(serializerName) - .getConstructor(Class.class) - .newInstance(jackson2ser); - Object module = - Class.forName(moduleName).getConstructor().newInstance(); + final String jackson2SerName = "com.fasterxml.jackson.databind.JsonSerializable"; + final String serializerName = "tools.jackson.databind.ser.jackson.RawSerializer"; + final String moduleName = "tools.jackson.databind.module.SimpleModule"; + final Class jackson2ser = Class.forName(jackson2SerName); + final Object serializer = + Class.forName(serializerName).getConstructor(Class.class).newInstance(jackson2ser); + Object module = Class.forName(moduleName).getConstructor().newInstance(); module = module.getClass().getMethod("addSerializer", serializer.getClass()).invoke(module, serializer); builder = @@ -111,8 +106,7 @@ public T patch( @Nonnull final T instance ) .getMethod("addModule", module.getClass()) .invoke(builder, module); } - catch( final - Exception e ) { + catch( final Exception e ) { log.debug("Could not find Jackson2 JsonSerializable class to add ToStringSerializer.", e); } return (T) new org.springframework.http.converter.json.JacksonJsonHttpMessageConverter(builder);