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();

Reply via email to