Skip to content

Commit

Permalink
GH-1196 Recactor registratio of Kotlin module
Browse files Browse the repository at this point in the history
Resolves #1196
  • Loading branch information
olegz committed Oct 23, 2024
1 parent 900d03f commit 3930cad
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.gson.Gson;
import io.cloudevents.spring.messaging.CloudEventMessageConverter;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
Expand Down Expand Up @@ -59,6 +61,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.core.KotlinDetector;
import org.springframework.core.ResolvableType;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.ConfigurableConversionService;
Expand Down Expand Up @@ -215,6 +218,7 @@ private JsonMapper gson(ApplicationContext context) {
return new GsonMapper(gson);
}

@SuppressWarnings("unchecked")
private JsonMapper jackson(ApplicationContext context) {
ObjectMapper mapper;
try {
Expand All @@ -225,6 +229,19 @@ private JsonMapper jackson(ApplicationContext context) {
mapper.registerModule(new JavaTimeModule());
}

if (KotlinDetector.isKotlinPresent()) {
try {
if (!mapper.getRegisteredModuleIds().contains("com.fasterxml.jackson.module.kotlin.KotlinModule")) {
Class<? extends Module> kotlinModuleClass = (Class<? extends Module>)
ClassUtils.forName("com.fasterxml.jackson.module.kotlin.KotlinModule", ClassUtils.getDefaultClassLoader());
Module kotlinModule = BeanUtils.instantiateClass(kotlinModuleClass);
mapper.registerModule(kotlinModule);
}
}
catch (ClassNotFoundException ex) {
// jackson-module-kotlin not available
}
}
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.configure(DeserializationFeature.FAIL_ON_TRAILING_TOKENS, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.util.function.Function;
import java.util.function.Supplier;

import com.fasterxml.jackson.module.kotlin.KotlinModule;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
Expand All @@ -37,14 +36,10 @@
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.cloud.function.context.FunctionRegistration;
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.util.ObjectUtils;

/**
Expand All @@ -62,19 +57,6 @@ public class KotlinLambdaToFunctionAutoConfiguration {

protected final Log logger = LogFactory.getLog(getClass());

@Bean
@ConditionalOnMissingBean
@ConditionalOnClass(name = {"org.springframework.http.converter.json.Jackson2ObjectMapperBuilder",
"com.fasterxml.jackson.module.kotlin.KotlinModule"})
Jackson2ObjectMapperBuilderCustomizer customizer() {
return new Jackson2ObjectMapperBuilderCustomizer() {
@Override
public void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder) {
jacksonObjectMapperBuilder.modulesToInstall(KotlinModule.class);
}
};
}


@SuppressWarnings({ "unchecked", "rawtypes" })
public static final class KotlinFunctionWrapper implements Function<Object, Object>, Supplier<Object>, Consumer<Object>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.cloud.function.utils;

import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.time.ZonedDateTime;
import java.util.Date;
Expand All @@ -38,6 +39,7 @@
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.ResolvableType;
import org.springframework.util.ReflectionUtils;

import static org.assertj.core.api.Assertions.assertThat;

Expand Down Expand Up @@ -84,6 +86,16 @@ public void testJsonDateTimeConversion() {
assertThat(convertedJson).contains("\"zonedDateTime\":\"2024-10-16T16:13:29.964361+02:00\"");
}

@Test
public void testKotlinModuleRegistration() throws Exception {
ApplicationContext context = SpringApplication.run(EmptyConfiguration.class);
JsonMapper jsonMapper = context.getBean(JsonMapper.class);
Field mapperField = ReflectionUtils.findField(jsonMapper.getClass(), "mapper");
mapperField.setAccessible(true);
ObjectMapper mapper = (ObjectMapper) mapperField.get(jsonMapper);
assertThat(mapper.getRegisteredModuleIds()).contains("com.fasterxml.jackson.module.kotlin.KotlinModule");
}

@ParameterizedTest
@MethodSource("params")
public void vanillaArray(JsonMapper mapper) {
Expand Down

0 comments on commit 3930cad

Please sign in to comment.