This is an automated email from the ASF dual-hosted git repository.
apkhmv pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new eca117a605 IGNITE-23648 Deserialize Instant objects as BigDecimals in
Micronaut (#4746)
eca117a605 is described below
commit eca117a6054c6e227603f5b63d38a8b7fd7b7199
Author: Vadim Pakhnushev <[email protected]>
AuthorDate: Wed Nov 20 15:38:45 2024 +0300
IGNITE-23648 Deserialize Instant objects as BigDecimals in Micronaut (#4746)
---
.../internal/cli/call/unit/UnitStatusRecord.java | 66 --------------------
.../internal/rest/InstantDeserializationTest.java | 71 ++++++++++++++++++++++
.../ignite/internal/rest/TimeController.java | 30 +++++++++
.../org/apache/ignite/internal/rest/TimeDto.java | 36 +++++++++++
.../apache/ignite/internal/rest/RestComponent.java | 4 ++
5 files changed, 141 insertions(+), 66 deletions(-)
diff --git
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusRecord.java
b/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusRecord.java
deleted file mode 100644
index bac9e8f890..0000000000
---
a/modules/cli/src/main/java/org/apache/ignite/internal/cli/call/unit/UnitStatusRecord.java
+++ /dev/null
@@ -1,66 +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.ignite.internal.cli.call.unit;
-
-import java.util.List;
-import java.util.Objects;
-import org.apache.ignite.rest.client.model.UnitVersionStatus;
-
-/** Unit status record. */
-public class UnitStatusRecord {
- private final String id;
- private final List<UnitVersionStatus> versionToStatus;
-
- UnitStatusRecord(String id, List<UnitVersionStatus> versionToStatus) {
- this.id = id;
- this.versionToStatus = versionToStatus;
- }
-
- public String id() {
- return id;
- }
-
- public List<UnitVersionStatus> versionToStatus() {
- return versionToStatus;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UnitStatusRecord that = (UnitStatusRecord) o;
- return Objects.equals(id, that.id) && Objects.equals(versionToStatus,
that.versionToStatus);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(id, versionToStatus);
- }
-
- @Override
- public String toString() {
- return "UnitStatusRecord{"
- + "id='" + id + '\''
- + ", versionToStatus=" + versionToStatus
- + '}';
- }
-}
diff --git
a/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/InstantDeserializationTest.java
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/InstantDeserializationTest.java
new file mode 100644
index 0000000000..076336d096
--- /dev/null
+++
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/InstantDeserializationTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ignite.internal.rest;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import io.micronaut.context.annotation.Property;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.client.HttpClient;
+import io.micronaut.http.client.annotation.Client;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import jakarta.inject.Inject;
+import java.time.Instant;
+import org.junit.jupiter.api.Test;
+
+@MicronautTest
+@Property(name = "micronaut.security.enabled", value = "false")
+@Property(name = "jackson.deserialization.use_big_decimal_for_floats", value =
"true")
+class InstantDeserializationTest {
+ // Specific value which will be truncated if deserialized as the double
+ private static final Instant INSTANT = Instant.ofEpochSecond(1730977056L,
232784600);
+
+ @Inject
+ @Client("/time")
+ HttpClient client;
+
+ @Test
+ void micronautDeserialization() {
+ // The TestController will deserialize the instant and return a string
representation.
+ String response = client.toBlocking().retrieve(HttpRequest.POST("/",
new TimeDto(INSTANT)));
+
+ assertThat(response, is(INSTANT.toString()));
+ }
+
+ @Test
+ void jacksonDeserialization() throws JsonProcessingException {
+ ObjectMapper mapper = new
ObjectMapper().enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
+ mapper.registerModule(new JavaTimeModule());
+
+ String serializedInstant = mapper.writeValueAsString(INSTANT);
+ assertThat(serializedInstant, is("1730977056.232784600"));
+
+ JsonNode jsonNode = mapper.readTree(serializedInstant);
+
+ Instant deserializedInstant = mapper.treeToValue(jsonNode,
Instant.class);
+
+ assertThat(deserializedInstant.getEpochSecond(),
is(INSTANT.getEpochSecond()));
+ assertThat(deserializedInstant.getNano(), is(INSTANT.getNano()));
+ }
+}
diff --git
a/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeController.java
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeController.java
new file mode 100644
index 0000000000..e2326e2fc4
--- /dev/null
+++
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeController.java
@@ -0,0 +1,30 @@
+/*
+ * 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.ignite.internal.rest;
+
+import io.micronaut.http.annotation.Body;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Post;
+
+@Controller("/time")
+class TimeController {
+ @Post
+ public static String time(@Body TimeDto time) {
+ return time.time().toString();
+ }
+}
diff --git
a/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeDto.java
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeDto.java
new file mode 100644
index 0000000000..59531461b2
--- /dev/null
+++
b/modules/rest-api/src/test/java/org/apache/ignite/internal/rest/TimeDto.java
@@ -0,0 +1,36 @@
+/*
+ * 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.ignite.internal.rest;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.time.Instant;
+
+class TimeDto {
+ private final Instant time;
+
+ @JsonCreator
+ TimeDto(@JsonProperty("time") Instant time) {
+ this.time = time;
+ }
+
+ @JsonProperty("time")
+ Instant time() {
+ return time;
+ }
+}
diff --git
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
index 6a5f20f161..d2aef6dba2 100644
---
a/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
+++
b/modules/rest/src/main/java/org/apache/ignite/internal/rest/RestComponent.java
@@ -20,6 +20,7 @@ package org.apache.ignite.internal.rest;
import static io.micronaut.context.env.Environment.BARE_METAL;
import static
org.apache.ignite.internal.util.CompletableFutures.nullCompletedFuture;
+import com.fasterxml.jackson.databind.DeserializationFeature;
import io.micronaut.context.ApplicationContext;
import io.micronaut.context.DefaultApplicationContext;
import io.micronaut.core.convert.ConversionService;
@@ -227,6 +228,9 @@ public class RestComponent implements IgniteComponent {
result.put("micronaut.security.intercept-url-map[0].pattern", "/**");
result.put("micronaut.security.intercept-url-map[0].access",
"isAuthenticated()");
+ // If deserialized as doubles, Instant objects can lose precision, see
InstantDeserializationTest
+ result.put("jackson.deserialization",
Map.of(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS, true));
+
if (sslEnabled) {
KeyStoreView keyStore = restSslView.keyStore();
boolean dualProtocol = restConfiguration.dualProtocol().value();