diff --git a/broker/pom.xml b/broker/pom.xml index 0983c4c8599b..dcba060cbbd7 100644 --- a/broker/pom.xml +++ b/broker/pom.xml @@ -31,11 +31,6 @@ jackson-datatype-jsr310 - - com.google.code.gson - gson - - com.google.guava guava diff --git a/broker/src/main/java/io/camunda/zeebe/broker/exporter/context/ExporterConfiguration.java b/broker/src/main/java/io/camunda/zeebe/broker/exporter/context/ExporterConfiguration.java index 4b13c6b9088d..64e3e10214d6 100644 --- a/broker/src/main/java/io/camunda/zeebe/broker/exporter/context/ExporterConfiguration.java +++ b/broker/src/main/java/io/camunda/zeebe/broker/exporter/context/ExporterConfiguration.java @@ -7,25 +7,27 @@ */ package io.camunda.zeebe.broker.exporter.context; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import io.camunda.zeebe.exporter.api.ExporterException; +import com.fasterxml.jackson.core.JsonParser.Feature; +import com.fasterxml.jackson.databind.MapperFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.json.JsonMapper; import io.camunda.zeebe.exporter.api.context.Configuration; +import io.camunda.zeebe.util.ReflectUtil; import java.util.Map; -public final class ExporterConfiguration implements Configuration { - private static final Gson CONFIG_INSTANTIATOR = new GsonBuilder().create(); +public record ExporterConfiguration(String id, Map arguments) + implements Configuration { - private final String id; - private final Map arguments; - - private JsonElement intermediateConfiguration; - - public ExporterConfiguration(final String id, final Map arguments) { - this.id = id; - this.arguments = arguments; - } + // Accepts more lenient cases, such that the property "something" would match a field "someThing" + // Note however that if a field "something" and "someThing" are present, only one of them will be + // instantiated (the last declared one), using the last matching value. + private static final ObjectMapper MAPPER = + JsonMapper.builder() + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES) + .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_VALUES) + .enable(Feature.IGNORE_UNDEFINED, Feature.ALLOW_SINGLE_QUOTES) + .build(); @Override public String getId() { @@ -40,25 +42,9 @@ public Map getArguments() { @Override public T instantiate(final Class configClass) { if (arguments != null) { - return CONFIG_INSTANTIATOR.fromJson(getIntermediateConfiguration(), configClass); + return MAPPER.convertValue(arguments, configClass); } else { - try { - return configClass.newInstance(); - } catch (final Exception e) { - throw new ExporterException( - "Unable to instantiate config class " - + configClass.getName() - + " with default constructor", - e); - } + return ReflectUtil.newInstance(configClass); } } - - private JsonElement getIntermediateConfiguration() { - if (intermediateConfiguration == null) { - intermediateConfiguration = CONFIG_INSTANTIATOR.toJsonTree(arguments); - } - - return intermediateConfiguration; - } } diff --git a/broker/src/main/java/io/camunda/zeebe/broker/exporter/repo/ExporterDescriptor.java b/broker/src/main/java/io/camunda/zeebe/broker/exporter/repo/ExporterDescriptor.java index 16d5dfa6f2ae..4577d52f5817 100644 --- a/broker/src/main/java/io/camunda/zeebe/broker/exporter/repo/ExporterDescriptor.java +++ b/broker/src/main/java/io/camunda/zeebe/broker/exporter/repo/ExporterDescriptor.java @@ -37,6 +37,6 @@ public ExporterConfiguration getConfiguration() { } public String getId() { - return configuration.getId(); + return configuration.id(); } } diff --git a/broker/src/test/java/io/camunda/zeebe/broker/exporter/context/ExporterConfigurationTest.java b/broker/src/test/java/io/camunda/zeebe/broker/exporter/context/ExporterConfigurationTest.java new file mode 100644 index 000000000000..3ebd6b0564c0 --- /dev/null +++ b/broker/src/test/java/io/camunda/zeebe/broker/exporter/context/ExporterConfigurationTest.java @@ -0,0 +1,53 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under + * one or more contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright ownership. + * Licensed under the Zeebe Community License 1.1. You may not use this file + * except in compliance with the Zeebe Community License 1.1. + */ +package io.camunda.zeebe.broker.exporter.context; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Map; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@Execution(ExecutionMode.CONCURRENT) +final class ExporterConfigurationTest { + @ParameterizedTest + @ValueSource(strings = {"numberofshards", "numberOfShards", "NUMBEROFSHARDS"}) + void shouldInstantiateConfigWithCaseInsensitiveProperties(final String property) { + // given + final var args = Map.of(property, 1); + final var expected = new Config(1); + final var config = new ExporterConfiguration("id", args); + + // when + final var instance = config.instantiate(Config.class); + + // then + assertThat(instance).isEqualTo(expected); + } + + @ParameterizedTest + @ValueSource(strings = {"numberofshards", "numberOfShards", "NUMBEROFSHARDS"}) + void shouldInstantiateNestedConfigWithCaseInsensitiveProperties(final String property) { + // given + final var args = Map.of("nested", Map.of(property, 1)); + final var expected = new ContainerConfig(new Config(1)); + final var config = new ExporterConfiguration("id", args); + + // when + final var instance = config.instantiate(ContainerConfig.class); + + // then + assertThat(instance).isEqualTo(expected); + } + + private record Config(int numberOfShards) {} + + private record ContainerConfig(Config nested) {} +} diff --git a/broker/src/test/java/io/camunda/zeebe/broker/exporter/repo/ExporterRepositoryTest.java b/broker/src/test/java/io/camunda/zeebe/broker/exporter/repo/ExporterRepositoryTest.java index 61ccdc1c26de..1c45f97a6aae 100644 --- a/broker/src/test/java/io/camunda/zeebe/broker/exporter/repo/ExporterRepositoryTest.java +++ b/broker/src/test/java/io/camunda/zeebe/broker/exporter/repo/ExporterRepositoryTest.java @@ -94,8 +94,8 @@ void shouldLoadExternalExporter(final @TempDir File tempDir) throws Exception { // then assertThat(config.isExternal()).isTrue(); - assertThat(descriptor.getConfiguration().getArguments()).isEqualTo(config.getArgs()); - assertThat(descriptor.getConfiguration().getId()).isEqualTo("exported"); + assertThat(descriptor.getConfiguration().arguments()).isEqualTo(config.getArgs()); + assertThat(descriptor.getConfiguration().id()).isEqualTo("exported"); assertThat(descriptor.newInstance().getClass().getCanonicalName()) .isEqualTo(ExternalExporter.EXPORTER_CLASS_NAME); } diff --git a/parent/pom.xml b/parent/pom.xml index 9c7c5dbcfa4f..c876793ecc9f 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -606,12 +606,6 @@ ${version.guava} - - com.google.code.gson - gson - ${version.gson} - - io.zeebe zeebe-test-container @@ -924,6 +918,13 @@ hamcrest-core ${version.hamcrest} + + + + com.google.code.gson + gson + ${version.gson} + diff --git a/qa/integration-tests/pom.xml b/qa/integration-tests/pom.xml index 0910b6e96eee..b1a915af9464 100644 --- a/qa/integration-tests/pom.xml +++ b/qa/integration-tests/pom.xml @@ -251,12 +251,6 @@ test - - org.springframework.boot - spring-boot - test - - org.mockito mockito-core diff --git a/qa/integration-tests/src/test/java/io/camunda/zeebe/it/smoke/StandaloneBrokerIT.java b/qa/integration-tests/src/test/java/io/camunda/zeebe/it/smoke/StandaloneBrokerIT.java index 3fdf5b8afe18..70da58db7be7 100644 --- a/qa/integration-tests/src/test/java/io/camunda/zeebe/it/smoke/StandaloneBrokerIT.java +++ b/qa/integration-tests/src/test/java/io/camunda/zeebe/it/smoke/StandaloneBrokerIT.java @@ -27,7 +27,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension;