This is an automated email from the ASF dual-hosted git repository.

adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 3c8f936e4cd HDDS-15808. Replace json-simple with Jackson in 
httpfsgateway (#10710)
3c8f936e4cd is described below

commit 3c8f936e4cdaa124cf2134acd8e30cf3b78a0022
Author: Siyao Meng <[email protected]>
AuthorDate: Fri Jul 10 11:13:47 2026 -0700

    HDDS-15808. Replace json-simple with Jackson in httpfsgateway (#10710)
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 hadoop-ozone/dist/src/main/license/bin/LICENSE.txt |   1 -
 hadoop-ozone/dist/src/main/license/jar-report.txt  |   1 -
 hadoop-ozone/httpfsgateway/pom.xml                 |  16 ++--
 .../apache/ozone/fs/http/server/FSOperations.java  | 106 ++++++++++-----------
 .../apache/ozone/fs/http/server/HttpFSServer.java  |  13 ++-
 .../instrumentation/InstrumentationService.java    |  64 +++----------
 .../org/apache/ozone/lib/wsrs/JSONMapProvider.java |   9 +-
 .../org/apache/ozone/lib/wsrs/JSONProvider.java    |  79 ---------------
 .../TestInstrumentationSerialization.java          |  78 +++++++++++++++
 .../apache/ozone/lib/wsrs/TestJSONMapProvider.java |  71 ++++++++++++++
 pom.xml                                            |   6 --
 11 files changed, 232 insertions(+), 212 deletions(-)

diff --git a/hadoop-ozone/dist/src/main/license/bin/LICENSE.txt 
b/hadoop-ozone/dist/src/main/license/bin/LICENSE.txt
index 0c509fa5964..8456581dfc2 100644
--- a/hadoop-ozone/dist/src/main/license/bin/LICENSE.txt
+++ b/hadoop-ozone/dist/src/main/license/bin/LICENSE.txt
@@ -298,7 +298,6 @@ Apache License 2.0
    com.google.inject.extensions:guice-servlet
    com.google.inject:guice
    com.google.j2objc:j2objc-annotations
-   com.googlecode.json-simple:json-simple
    com.jolbox:bonecp
    com.lmax:disruptor
    com.nimbusds:nimbus-jose-jwt
diff --git a/hadoop-ozone/dist/src/main/license/jar-report.txt 
b/hadoop-ozone/dist/src/main/license/jar-report.txt
index 274f5385721..1ab2063cf5c 100644
--- a/hadoop-ozone/dist/src/main/license/jar-report.txt
+++ b/hadoop-ozone/dist/src/main/license/jar-report.txt
@@ -165,7 +165,6 @@ share/ozone/lib/jooq-codegen.jar
 share/ozone/lib/jooq-meta.jar
 share/ozone/lib/jooq.jar
 share/ozone/lib/jsch.jar
-share/ozone/lib/json-simple.jar
 share/ozone/lib/jsp-api.jar
 share/ozone/lib/jspecify.jar
 share/ozone/lib/jsr311-api.jar
diff --git a/hadoop-ozone/httpfsgateway/pom.xml 
b/hadoop-ozone/httpfsgateway/pom.xml
index 4da62ff003f..a8562e52c14 100644
--- a/hadoop-ozone/httpfsgateway/pom.xml
+++ b/hadoop-ozone/httpfsgateway/pom.xml
@@ -44,17 +44,15 @@
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
+      <artifactId>jackson-annotations</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-core</artifactId>
     </dependency>
     <dependency>
-      <groupId>com.googlecode.json-simple</groupId>
-      <artifactId>json-simple</artifactId>
-      <exclusions>
-        <exclusion>
-          <groupId>junit</groupId>
-          <artifactId>junit</artifactId>
-        </exclusion>
-      </exclusions>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
     </dependency>
     <dependency>
       <groupId>jakarta.ws.rs</groupId>
diff --git 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/FSOperations.java
 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/FSOperations.java
index 55d90ef9901..eb2998e9cf6 100644
--- 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/FSOperations.java
+++ 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/FSOperations.java
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.LinkedHashMap;
@@ -60,8 +61,6 @@
 import org.apache.ozone.fs.http.HttpFSConstants;
 import org.apache.ozone.fs.http.HttpFSConstants.FILETYPE;
 import org.apache.ozone.lib.service.FileSystemAccess;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
 
 /**
  * FileSystem operation executors used by {@link HttpFSServer}.
@@ -107,7 +106,7 @@ private static Map<String, Object> toJson(FileStatus[] 
fileStatuses,
       boolean isFile) {
     Map<String, Object> json = new LinkedHashMap<>();
     Map<String, Object> inner = new LinkedHashMap<>();
-    JSONArray statuses = new JSONArray();
+    List<Map<String, Object>> statuses = new ArrayList<>();
     for (FileStatus f : fileStatuses) {
       statuses.add(toJsonInner(f, isFile));
     }
@@ -209,7 +208,7 @@ private static Map<String, Object> 
toJson(FileSystem.DirectoryEntries
   private static Map<String, Object> aclStatusToJSON(AclStatus aclStatus) {
     Map<String, Object> json = new LinkedHashMap<String, Object>();
     Map<String, Object> inner = new LinkedHashMap<String, Object>();
-    JSONArray entriesArray = new JSONArray();
+    List<String> entriesArray = new ArrayList<>();
     inner.put(HttpFSConstants.OWNER_JSON, aclStatus.getOwner());
     inner.put(HttpFSConstants.GROUP_JSON, aclStatus.getGroup());
     inner.put(HttpFSConstants.PERMISSION_JSON,
@@ -254,14 +253,13 @@ private static Map fileChecksumToJSON(FileChecksum 
checksum) {
    * @return The JSON representation of the xAttrs.
    * @throws IOException 
    */
-  @SuppressWarnings({"unchecked", "rawtypes"})
-  private static Map xAttrsToJSON(Map<String, byte[]> xAttrs, 
+  private static Map<String, Object> xAttrsToJSON(Map<String, byte[]> xAttrs,
       XAttrCodec encoding) throws IOException {
-    Map jsonMap = new LinkedHashMap();
-    JSONArray jsonArray = new JSONArray();
+    Map<String, Object> jsonMap = new LinkedHashMap<>();
+    List<Map<String, Object>> jsonArray = new ArrayList<>();
     if (xAttrs != null) {
       for (Entry<String, byte[]> e : xAttrs.entrySet()) {
-        Map json = new LinkedHashMap();
+        Map<String, Object> json = new LinkedHashMap<>();
         json.put(HttpFSConstants.XATTR_NAME_JSON, e.getKey());
         if (e.getValue() != null) {
           json.put(HttpFSConstants.XATTR_VALUE_JSON,
@@ -286,7 +284,7 @@ private static Map xAttrsToJSON(Map<String, byte[]> xAttrs,
   private static Map xAttrNamesToJSON(List<String> names) throws IOException {
     Map jsonMap = new LinkedHashMap();
     jsonMap.put(HttpFSConstants.XATTRNAMES_JSON,
-        JSONArray.toJSONString(names));
+        JsonUtil.toJsonString(names));
     return jsonMap;
   }
 
@@ -364,27 +362,26 @@ private static Map<String, Object> 
quotaUsageToMap(QuotaUsage quotaUsage) {
   }
 
   /**
-   * Converts an object into a Json Map with with one key-value entry.
+   * Converts an object into a Json Map with one key-value entry.
    * <p/>
-   * It assumes the given value is either a JSON primitive type or a
-   * <code>JsonAware</code> instance.
+   * The value may be a JSON primitive, a Map or List, or any object that
+   * Jackson can serialize.
    *
    * @param name name for the key of the entry.
    * @param value for the value of the entry.
    *
    * @return the JSON representation of the key-value pair.
    */
-  @SuppressWarnings("unchecked")
-  private static JSONObject toJSON(String name, Object value) {
-    JSONObject json = new JSONObject();
+  private static Map<String, Object> toJSON(String name, Object value) {
+    Map<String, Object> json = new LinkedHashMap<>();
     json.put(name, value);
     return json;
   }
 
-  @SuppressWarnings({ "unchecked" })
-  private static JSONObject storagePolicyToJSON(BlockStoragePolicySpi policy) {
+  private static Map<String, Object> storagePolicyToJSON(
+      BlockStoragePolicySpi policy) {
     BlockStoragePolicy p = (BlockStoragePolicy) policy;
-    JSONObject policyJson = new JSONObject();
+    Map<String, Object> policyJson = new LinkedHashMap<>();
     policyJson.put("id", p.getId());
     policyJson.put("name", p.getName());
     policyJson.put("storageTypes", toJsonArray(p.getStorageTypes()));
@@ -395,24 +392,22 @@ private static JSONObject 
storagePolicyToJSON(BlockStoragePolicySpi policy) {
     return policyJson;
   }
 
-  @SuppressWarnings("unchecked")
-  private static JSONArray toJsonArray(StorageType[] storageTypes) {
-    JSONArray jsonArray = new JSONArray();
+  private static List<String> toJsonArray(StorageType[] storageTypes) {
+    List<String> jsonArray = new ArrayList<>();
     for (StorageType type : storageTypes) {
       jsonArray.add(type.toString());
     }
     return jsonArray;
   }
 
-  @SuppressWarnings("unchecked")
-  private static JSONObject storagePoliciesToJSON(
+  private static Map<String, Object> storagePoliciesToJSON(
       Collection<? extends BlockStoragePolicySpi> storagePolicies) {
-    JSONObject json = new JSONObject();
-    JSONArray jsonArray = new JSONArray();
-    JSONObject policies = new JSONObject();
+    Map<String, Object> json = new LinkedHashMap<>();
+    List<Map<String, Object>> jsonArray = new ArrayList<>();
+    Map<String, Object> policies = new LinkedHashMap<>();
     if (storagePolicies != null) {
       for (BlockStoragePolicySpi policy : storagePolicies) {
-        JSONObject policyMap = storagePolicyToJSON(policy);
+        Map<String, Object> policyMap = storagePolicyToJSON(policy);
         jsonArray.add(policyMap);
       }
     }
@@ -507,8 +502,8 @@ public Void execute(FileSystem fs) throws IOException {
    * Executor that performs a truncate FileSystemAccess files system operation.
    */
   @InterfaceAudience.Private
-  public static class FSTruncate implements 
-      FileSystemAccess.FileSystemExecutor<JSONObject> {
+  public static class FSTruncate implements
+      FileSystemAccess.FileSystemExecutor<Map> {
     private Path path;
     private long newLength;
 
@@ -537,7 +532,7 @@ public FSTruncate(String path, long newLength) {
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       boolean result = fs.truncate(path, newLength);
       HttpFSServerWebApp.get().getMetrics().incrOpsTruncate();
       return toJSON(
@@ -730,7 +725,7 @@ public static long copyBytes(InputStream in, OutputStream 
out, long count)
    */
   @InterfaceAudience.Private
   public static class FSDelete
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
     private Path path;
     private boolean recursive;
 
@@ -756,7 +751,7 @@ public FSDelete(String path, boolean recursive) {
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       boolean deleted = fs.delete(path, recursive);
       HttpFSServerWebApp.get().getMetrics().incrOpsDelete();
       return toJSON(
@@ -842,7 +837,7 @@ public Map execute(FileSystem fs) throws IOException {
    */
   @InterfaceAudience.Private
   public static class FSHomeDir
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
 
     /**
      * Executes the filesystem operation.
@@ -854,10 +849,9 @@ public static class FSHomeDir
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       Path homeDir = fs.getHomeDirectory();
-      JSONObject json = new JSONObject();
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put(HttpFSConstants.HOME_DIR_JSON, homeDir.toUri().getPath());
       return json;
     }
@@ -955,7 +949,7 @@ public Map execute(FileSystem fs) throws IOException {
    */
   @InterfaceAudience.Private
   public static class FSMkdirs
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
 
     private Path path;
     private short permission;
@@ -986,7 +980,7 @@ public FSMkdirs(String path, short permission,
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       FsPermission fsPermission = new FsPermission(permission);
       if (unmaskedPermission != -1) {
         fsPermission = FsCreateModes.create(fsPermission,
@@ -1039,7 +1033,7 @@ public InputStream execute(FileSystem fs) throws 
IOException {
    */
   @InterfaceAudience.Private
   public static class FSRename
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
     private Path path;
     private Path toPath;
 
@@ -1065,7 +1059,7 @@ public FSRename(String path, String toPath) {
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       boolean renamed = fs.rename(path, toPath);
       HttpFSServerWebApp.get().getMetrics().incrOpsRename();
       return toJSON(HttpFSConstants.RENAME_JSON, renamed);
@@ -1343,7 +1337,7 @@ public Void execute(FileSystem fs) throws IOException {
    */
   @InterfaceAudience.Private
   public static class FSTrashRoot
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
     private Path path;
 
     public FSTrashRoot(String path) {
@@ -1351,10 +1345,9 @@ public FSTrashRoot(String path) {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       Path trashRoot = fs.getTrashRoot(this.path);
-      JSONObject json = new JSONObject();
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put(HttpFSConstants.TRASH_DIR_JSON, trashRoot.toUri().getPath());
       return json;
     }
@@ -1401,7 +1394,7 @@ public Map execute(FileSystem fs) throws IOException {
    */
   @InterfaceAudience.Private
   public static class FSSetReplication
-      implements FileSystemAccess.FileSystemExecutor<JSONObject> {
+      implements FileSystemAccess.FileSystemExecutor<Map> {
     private Path path;
     private short replication;
 
@@ -1427,10 +1420,9 @@ public FSSetReplication(String path, short replication) {
      * @throws IOException thrown if an IO error occurred.
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       boolean ret = fs.setReplication(path, replication);
-      JSONObject json = new JSONObject();
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put(HttpFSConstants.SET_REPLICATION_JSON, ret);
       return json;
     }
@@ -1610,13 +1602,12 @@ public Map execute(FileSystem fs) throws IOException {
    * Executor that performs a getAllStoragePolicies FileSystemAccess files
    * system operation.
    */
-  @SuppressWarnings({ "unchecked" })
   @InterfaceAudience.Private
   public static class FSGetAllStoragePolicies implements
-      FileSystemAccess.FileSystemExecutor<JSONObject> {
+      FileSystemAccess.FileSystemExecutor<Map> {
 
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       Collection<? extends BlockStoragePolicySpi> storagePolicies = fs
           .getAllStoragePolicies();
       return storagePoliciesToJSON(storagePolicies);
@@ -1627,10 +1618,9 @@ public JSONObject execute(FileSystem fs) throws 
IOException {
    * Executor that performs a getStoragePolicy FileSystemAccess files system
    * operation.
    */
-  @SuppressWarnings({ "unchecked" })
   @InterfaceAudience.Private
   public static class FSGetStoragePolicy implements
-      FileSystemAccess.FileSystemExecutor<JSONObject> {
+      FileSystemAccess.FileSystemExecutor<Map> {
 
     private Path path;
 
@@ -1639,9 +1629,9 @@ public FSGetStoragePolicy(String path) {
     }
 
     @Override
-    public JSONObject execute(FileSystem fs) throws IOException {
+    public Map execute(FileSystem fs) throws IOException {
       BlockStoragePolicySpi storagePolicy = fs.getStoragePolicy(path);
-      JSONObject json = new JSONObject();
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put(HttpFSConstants.STORAGE_POLICY_JSON,
           storagePolicyToJSON(storagePolicy));
       return json;
@@ -1793,9 +1783,9 @@ public FSCreateSnapshot(String path, String snapshotName) 
{
     @Override
     public String execute(FileSystem fs) throws IOException {
       Path snapshotPath = fs.createSnapshot(path, snapshotName);
-      JSONObject json = toJSON(HttpFSConstants.HOME_DIR_JSON,
+      Map<String, Object> json = toJSON(HttpFSConstants.HOME_DIR_JSON,
           snapshotPath.toString());
-      return json.toJSONString().replaceAll("\\\\", "");
+      return JsonUtil.toJsonString(json);
     }
   }
 
diff --git 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/HttpFSServer.java
 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/HttpFSServer.java
index 262b9fa6945..c6ac62a7f3f 100644
--- 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/HttpFSServer.java
+++ 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/fs/http/server/HttpFSServer.java
@@ -83,7 +83,6 @@
 import org.apache.ozone.lib.servlet.FileSystemReleaseFilter;
 import org.apache.ozone.lib.wsrs.InputStreamEntity;
 import org.apache.ozone.lib.wsrs.Parameters;
-import org.json.simple.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.MDC;
@@ -402,7 +401,7 @@ private Response handleGetStoragePolicy(String path,
     Response response;
     FSOperations.FSGetStoragePolicy command =
         new FSOperations.FSGetStoragePolicy(path);
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     AUDIT_LOG.info("[{}]", path);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
     return response;
@@ -414,7 +413,7 @@ private Response handleGetAllStoragePolicy(String path,
     Response response;
     FSOperations.FSGetAllStoragePolicies command =
         new FSOperations.FSGetAllStoragePolicies();
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     AUDIT_LOG.info("[{}]", path);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
     return response;
@@ -649,7 +648,7 @@ private Response handleDelete(String path,
     AUDIT_LOG.info("[{}] recursive [{}]", path, recursive);
     FSOperations.FSDelete command
         = new FSOperations.FSDelete(path, recursive);
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
     return response;
   }
@@ -769,7 +768,7 @@ private Response handleTruncate(String path,
     Long newLength = params.get(NewLengthParam.NAME, NewLengthParam.class);
     FSOperations.FSTruncate command
         = new FSOperations.FSTruncate(path, newLength);
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     AUDIT_LOG.info("Truncate [{}] to length [{}]", path, newLength);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
     return response;
@@ -1078,7 +1077,7 @@ private Response handleRename(String path,
     String toPath = params.get(DestinationParam.NAME, DestinationParam.class);
     FSOperations.FSRename command
         = new FSOperations.FSRename(path, toPath);
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     AUDIT_LOG.info("[{}] to [{}]", path, toPath);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
     return response;
@@ -1095,7 +1094,7 @@ private Response handleMkdirs(String path,
         UnmaskedPermissionParam.class);
     FSOperations.FSMkdirs command =
         new FSOperations.FSMkdirs(path, permission, unmaskedPermission);
-    JSONObject json = fsExecute(user, command);
+    Map json = fsExecute(user, command);
     AUDIT_LOG.info("[{}] permission [{}] unmaskedpermission [{}]",
         path, permission, unmaskedPermission);
     response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
diff --git 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/service/instrumentation/InstrumentationService.java
 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/service/instrumentation/InstrumentationService.java
index 28b87518f34..d441df55efd 100644
--- 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/service/instrumentation/InstrumentationService.java
+++ 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/service/instrumentation/InstrumentationService.java
@@ -17,8 +17,7 @@
 
 package org.apache.ozone.lib.service.instrumentation;
 
-import java.io.IOException;
-import java.io.Writer;
+import com.fasterxml.jackson.annotation.JsonValue;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -34,9 +33,6 @@
 import org.apache.ozone.lib.server.ServiceException;
 import org.apache.ozone.lib.service.Instrumentation;
 import org.apache.ozone.lib.service.Scheduler;
-import org.json.simple.JSONAware;
-import org.json.simple.JSONObject;
-import org.json.simple.JSONStreamAware;
 
 /**
  * Hadoop server instrumentation.
@@ -195,7 +191,7 @@ void end() {
 
   }
 
-  static class Timer implements JSONAware, JSONStreamAware {
+  static class Timer {
     static final int LAST_TOTAL = 0;
     static final int LAST_OWN = 1;
     static final int AVG_TOTAL = 2;
@@ -251,10 +247,10 @@ void addCron(Cron cron) {
       }
     }
 
-    @SuppressWarnings("unchecked")
-    private JSONObject getJSON() {
+    @JsonValue
+    Map<String, Object> getJSON() {
       long[] values = getValues();
-      JSONObject json = new JSONObject();
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put("lastTotal", values[0]);
       json.put("lastOwn", values[1]);
       json.put("avgTotal", values[2]);
@@ -262,16 +258,6 @@ private JSONObject getJSON() {
       return json;
     }
 
-    @Override
-    public String toJSONString() {
-      return getJSON().toJSONString();
-    }
-
-    @Override
-    public void writeJSONString(Writer out) throws IOException {
-      getJSON().writeJSONString(out);
-    }
-
   }
 
   @Override
@@ -295,9 +281,9 @@ public void addCron(String group, String name, 
Instrumentation.Cron cron) {
     timer.addCron((Cron) cron);
   }
 
-  static class VariableHolder<E> implements JSONAware, JSONStreamAware {
-    // Supressed, because it is only used in this class or in test files,
-    // but the tests will be removed later.
+  static class VariableHolder<E> {
+    // Package-private and mutable so the enclosing service can assign it
+    // directly; suppress the visibility check.
     @SuppressWarnings("checkstyle:VisibilityModifier")
     Variable<E> var;
 
@@ -308,23 +294,13 @@ static class VariableHolder<E> implements JSONAware, 
JSONStreamAware {
       this.var = var;
     }
 
-    @SuppressWarnings("unchecked")
-    private JSONObject getJSON() {
-      JSONObject json = new JSONObject();
+    @JsonValue
+    Map<String, Object> getJSON() {
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put("value", var.getValue());
       return json;
     }
 
-    @Override
-    public String toJSONString() {
-      return getJSON().toJSONString();
-    }
-
-    @Override
-    public void writeJSONString(Writer out) throws IOException {
-      out.write(toJSONString());
-    }
-
   }
 
   @Override
@@ -334,7 +310,7 @@ public void addVariable(String group, String name, 
Variable<?> variable) {
     holder.var = variable;
   }
 
-  static class Sampler implements JSONAware, JSONStreamAware {
+  static class Sampler {
     private Variable<Long> variable;
     private long[] values;
     private AtomicLong sum;
@@ -362,23 +338,13 @@ void sample() {
           ((full) ? values.length : ((last == 0) ? 1 : last));
     }
 
-    @SuppressWarnings("unchecked")
-    private JSONObject getJSON() {
-      JSONObject json = new JSONObject();
+    @JsonValue
+    Map<String, Object> getJSON() {
+      Map<String, Object> json = new LinkedHashMap<>();
       json.put("sampler", getRate());
       json.put("size", (full) ? values.length : last);
       return json;
     }
-
-    @Override
-    public String toJSONString() {
-      return getJSON().toJSONString();
-    }
-
-    @Override
-    public void writeJSONString(Writer out) throws IOException {
-      out.write(toJSONString());
-    }
   }
 
   @Override
diff --git 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONMapProvider.java
 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONMapProvider.java
index bdb75490f83..232993effe6 100644
--- 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONMapProvider.java
+++ 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONMapProvider.java
@@ -17,6 +17,8 @@
 
 package org.apache.ozone.lib.wsrs;
 
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -33,7 +35,6 @@
 import javax.ws.rs.ext.Provider;
 import org.apache.hadoop.hdds.annotation.InterfaceAudience;
 import org.apache.hadoop.http.JettyUtils;
-import org.json.simple.JSONObject;
 
 /**
  * A <code>MessageBodyWriter</code> implementation providing a JSON map.
@@ -43,6 +44,10 @@
 @InterfaceAudience.Private
 public class JSONMapProvider implements MessageBodyWriter<Map> {
   private static final String ENTER = System.getProperty("line.separator");
+  // AUTO_CLOSE_TARGET is disabled so the underlying response stream stays
+  // open for the trailing newline and container-managed close.
+  private static final ObjectMapper MAPPER = new ObjectMapper()
+      .disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
 
   @Override
   public boolean isWriteable(Class<?> aClass,
@@ -72,7 +77,7 @@ public void writeTo(Map map,
       throws IOException, WebApplicationException {
     Writer writer
         = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
-    JSONObject.writeJSONString(map, writer);
+    MAPPER.writeValue(writer, map);
     writer.write(ENTER);
     writer.flush();
   }
diff --git 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONProvider.java
 
b/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONProvider.java
deleted file mode 100644
index b98d4db19f1..00000000000
--- 
a/hadoop-ozone/httpfsgateway/src/main/java/org/apache/ozone/lib/wsrs/JSONProvider.java
+++ /dev/null
@@ -1,79 +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.ozone.lib.wsrs;
-
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Type;
-import java.nio.charset.StandardCharsets;
-import javax.ws.rs.Produces;
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.ext.MessageBodyWriter;
-import javax.ws.rs.ext.Provider;
-import org.apache.hadoop.hdds.annotation.InterfaceAudience;
-import org.apache.hadoop.http.JettyUtils;
-import org.json.simple.JSONStreamAware;
-
-/**
- * A <code>MessageBodyWriter</code> implementation providing a JSON stream.
- */
-@Provider
-@Produces(MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8)
[email protected]
-public class JSONProvider implements MessageBodyWriter<JSONStreamAware> {
-  private static final String ENTER = System.getProperty("line.separator");
-
-  @Override
-  public boolean isWriteable(Class<?> aClass,
-                             Type type,
-                             Annotation[] annotations,
-                             MediaType mediaType) {
-    return JSONStreamAware.class.isAssignableFrom(aClass);
-  }
-
-  @Override
-  public long getSize(JSONStreamAware jsonStreamAware,
-                      Class<?> aClass,
-                      Type type,
-                      Annotation[] annotations,
-                      MediaType mediaType) {
-    return -1;
-  }
-
-  @Override
-  public void writeTo(JSONStreamAware jsonStreamAware,
-                      Class<?> aClass,
-                      Type type,
-                      Annotation[] annotations,
-                      MediaType mediaType,
-                      MultivaluedMap<String, Object> 
stringObjectMultivaluedMap,
-                      OutputStream outputStream)
-      throws IOException, WebApplicationException {
-    Writer writer
-        = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
-    jsonStreamAware.writeJSONString(writer);
-    writer.write(ENTER);
-    writer.flush();
-  }
-
-}
diff --git 
a/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/service/instrumentation/TestInstrumentationSerialization.java
 
b/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/service/instrumentation/TestInstrumentationSerialization.java
new file mode 100644
index 00000000000..19f0d033981
--- /dev/null
+++ 
b/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/service/instrumentation/TestInstrumentationSerialization.java
@@ -0,0 +1,78 @@
+/*
+ * 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.ozone.lib.service.instrumentation;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ozone.lib.service.Instrumentation;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Verifies that the {@code @JsonValue}-annotated snapshot types in
+ * {@link InstrumentationService} serialize to the same JSON shape that the
+ * former json-simple based serialization produced.
+ */
+public class TestInstrumentationSerialization {
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  @Test
+  public void testTimerSerialization() {
+    InstrumentationService.Cron cron = new InstrumentationService.Cron();
+    cron.start();
+    cron.stop();
+    InstrumentationService.Timer timer = new InstrumentationService.Timer(10);
+    timer.addCron(cron);
+
+    JsonNode node = MAPPER.valueToTree(timer);
+    assertThat(node.isObject()).isTrue();
+    assertThat(node.fieldNames()).toIterable()
+        .containsExactly("lastTotal", "lastOwn", "avgTotal", "avgOwn");
+    assertThat(node.get("lastTotal").isNumber()).isTrue();
+    assertThat(node.get("avgOwn").isNumber()).isTrue();
+  }
+
+  @Test
+  public void testVariableHolderSerialization() {
+    InstrumentationService.VariableHolder<Long> holder =
+        new InstrumentationService.VariableHolder<>(
+            (Instrumentation.Variable<Long>) () -> 42L);
+
+    JsonNode node = MAPPER.valueToTree(holder);
+    assertThat(node.isObject()).isTrue();
+    assertThat(node.fieldNames()).toIterable().containsExactly("value");
+    assertThat(node.get("value").asLong()).isEqualTo(42L);
+  }
+
+  @Test
+  public void testSamplerSerialization() {
+    InstrumentationService.Sampler sampler =
+        new InstrumentationService.Sampler();
+    sampler.init(4, () -> 7L);
+    sampler.sample();
+
+    JsonNode node = MAPPER.valueToTree(sampler);
+    assertThat(node.isObject()).isTrue();
+    assertThat(node.fieldNames()).toIterable()
+        .containsExactly("sampler", "size");
+    assertThat(node.get("sampler").isNumber()).isTrue();
+    assertThat(node.get("size").asInt()).isEqualTo(1);
+  }
+}
diff --git 
a/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/wsrs/TestJSONMapProvider.java
 
b/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/wsrs/TestJSONMapProvider.java
new file mode 100644
index 00000000000..606f3145430
--- /dev/null
+++ 
b/hadoop-ozone/httpfsgateway/src/test/java/org/apache/ozone/lib/wsrs/TestJSONMapProvider.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.ozone.lib.wsrs;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link JSONMapProvider} JSON output framing after the json-simple to
+ * Jackson migration.
+ */
+public class TestJSONMapProvider {
+
+  private String writeToString(Map<String, Object> map, ByteArrayOutputStream 
out)
+      throws IOException {
+    new JSONMapProvider().writeTo(map, Map.class, Map.class, null, null, null, 
out);
+    return new String(out.toByteArray(), StandardCharsets.UTF_8);
+  }
+
+  @Test
+  public void testWriteToEmitsJsonWithTrailingNewline() throws IOException {
+    Map<String, Object> map = new LinkedHashMap<>();
+    map.put("boolean", true);
+    map.put("long", 42L);
+    map.put("string", "value");
+
+    String output = writeToString(map, new ByteArrayOutputStream());
+    assertThat(output).isEqualTo(
+        "{\"boolean\":true,\"long\":42,\"string\":\"value\"}"
+            + System.getProperty("line.separator"));
+  }
+
+  @Test
+  public void testWriteToDoesNotCloseUnderlyingStream() throws IOException {
+    AtomicBoolean closed = new AtomicBoolean(false);
+    ByteArrayOutputStream out = new ByteArrayOutputStream() {
+      @Override
+      public void close() {
+        closed.set(true);
+      }
+    };
+
+    Map<String, Object> map = new LinkedHashMap<>();
+    map.put("k", "v");
+    writeToString(map, out);
+
+    assertThat(closed).isFalse();
+  }
+}
diff --git a/pom.xml b/pom.xml
index 093e0519875..ba1b1ea64b7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,7 +118,6 @@
     <joda.time.version>2.12.7</joda.time.version>
     <jooq.version>3.11.10</jooq.version>
     <jsch.version>0.1.55</jsch.version>
-    <json-simple.version>1.1.1</json-simple.version>
     <jsp-api.version>2.1</jsp-api.version>
     <jsr311-api.version>1.1.1</jsr311-api.version>
     <junit5.version>5.14.4</junit5.version>
@@ -456,11 +455,6 @@
         <artifactId>compile-testing</artifactId>
         <version>${compile-testing.version}</version>
       </dependency>
-      <dependency>
-        <groupId>com.googlecode.json-simple</groupId>
-        <artifactId>json-simple</artifactId>
-        <version>${json-simple.version}</version>
-      </dependency>
       <dependency>
         <groupId>com.jcraft</groupId>
         <artifactId>jsch</artifactId>


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]


Reply via email to