#211: Handle Collections and Maps containing JsonValues

JsonArrayBuilder and JsonObjectBuilder add methods handle
JsonValues and JsonArrayBuilder and JsonObjectBuilder instances,
but creating builders using a Collection or Map that contains
these values fails, because MapUtil does not handle them and
throws an IllegalArgumentException saying that the types are
not supported.

This commit includes tests that create builders with such
values and changes to MapUtil to handle them. (It also
refactors MapUtil to avoid unnecessary excessive nesting.)

Signed-off-by: Todd O'Bryan <toddobryan@gmail.com>
Also-by: Lukas Jungmann <lukas.jungmann@oracle.com>
diff --git a/impl/src/main/java/org/glassfish/json/MapUtil.java b/impl/src/main/java/org/glassfish/json/MapUtil.java
index da505bb..b28a1ff 100644
--- a/impl/src/main/java/org/glassfish/json/MapUtil.java
+++ b/impl/src/main/java/org/glassfish/json/MapUtil.java
@@ -38,51 +38,38 @@
     }
 
     static JsonValue handle(Object value, BufferPool bufferPool) {
-
         if (value == null) {
             return JsonValue.NULL;
-        }
-
-        if (value instanceof BigDecimal) {
+        } else if (value instanceof JsonValue) {
+            return (JsonValue) value;
+        } else if (value instanceof JsonArrayBuilder) {
+            return ((JsonArrayBuilder) value).build();
+        } else if (value instanceof JsonObjectBuilder) {
+            return ((JsonObjectBuilder) value).build();
+        } else if (value instanceof BigDecimal) {
             return JsonNumberImpl.getJsonNumber((BigDecimal) value);
-        } else {
-            if (value instanceof BigInteger) {
-                return JsonNumberImpl.getJsonNumber((BigInteger) value);
-            } else {
-                if ( value instanceof Boolean) {
-                    Boolean b = (Boolean) value;
-                    return b ? JsonValue.TRUE : JsonValue.FALSE;
-                } else {
-                    if (value instanceof Double) {
-                        return JsonNumberImpl.getJsonNumber((Double) value);
-                    } else {
-                        if (value instanceof Integer) {
-                            return JsonNumberImpl.getJsonNumber((Integer) value);
-                        } else {
-                            if (value instanceof Long) {
-                                return JsonNumberImpl.getJsonNumber((Long) value);
-                            } else {
-                                if (value instanceof String) {
-                                    return new JsonStringImpl((String) value);
-                                } else {
-                                    if (value instanceof Collection) {
-                                        @SuppressWarnings("unchecked")
-                                        Collection<?> collection = (Collection<?>) value;
-                                        JsonArrayBuilder jsonArrayBuilder = new JsonArrayBuilderImpl(collection, bufferPool);
-                                        return jsonArrayBuilder.build();
-                                    } else {
-                                        if (value instanceof Map) {
-                                            @SuppressWarnings("unchecked")
-                                            JsonObjectBuilder object = new JsonObjectBuilderImpl((Map<String, Object>) value, bufferPool);
-                                            return object.build();
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
+        } else if (value instanceof BigInteger) {
+            return JsonNumberImpl.getJsonNumber((BigInteger) value);
+        } else if (value instanceof Boolean) {
+            Boolean b = (Boolean) value;
+            return b ? JsonValue.TRUE : JsonValue.FALSE;
+        } else if (value instanceof Double) {
+            return JsonNumberImpl.getJsonNumber((Double) value);
+        } else if (value instanceof Integer) {
+            return JsonNumberImpl.getJsonNumber((Integer) value);
+        } else if (value instanceof Long) {
+            return JsonNumberImpl.getJsonNumber((Long) value);
+        } else if (value instanceof String) {
+            return new JsonStringImpl((String) value);
+        } else if (value instanceof Collection) {
+            @SuppressWarnings("unchecked")
+            Collection<?> collection = (Collection<?>) value;
+            JsonArrayBuilder jsonArrayBuilder = new JsonArrayBuilderImpl(collection, bufferPool);
+            return jsonArrayBuilder.build();
+        } else if (value instanceof Map) {
+            @SuppressWarnings("unchecked")
+            JsonObjectBuilder object = new JsonObjectBuilderImpl((Map<String, Object>) value, bufferPool);
+            return object.build();
         }
 
         throw new IllegalArgumentException(String.format("Type %s is not supported.", value.getClass()));
diff --git a/impl/src/test/java/org/glassfish/json/tests/JsonArrayTest.java b/impl/src/test/java/org/glassfish/json/tests/JsonArrayTest.java
index f74bd49..fa2d9d1 100644
--- a/impl/src/test/java/org/glassfish/json/tests/JsonArrayTest.java
+++ b/impl/src/test/java/org/glassfish/json/tests/JsonArrayTest.java
@@ -21,6 +21,7 @@
 import jakarta.json.*;
 import java.io.StringReader;
 import java.io.StringWriter;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -42,6 +43,8 @@
                 .add(Integer.MIN_VALUE)
                 .add(Long.MIN_VALUE)
                 .add(Double.MIN_VALUE)
+                .add(Json.createArrayBuilder().add("abc"))
+                .add(Json.createObjectBuilder().add("one", 1))
                 .build();
 
         StringWriter sw = new StringWriter();
@@ -56,6 +59,34 @@
         assertEquals(expected, actual);
     }
 
+    public void testArrayEqualsUsingCollection() {
+        List<Object> list = new ArrayList<>();
+        list.add(JsonValue.TRUE);
+        list.add(JsonValue.FALSE);
+        list.add(JsonValue.NULL);
+        list.add(Integer.MAX_VALUE);
+        list.add(Long.MAX_VALUE);
+        list.add(Double.MAX_VALUE);
+        list.add(Integer.MIN_VALUE);
+        list.add(Long.MIN_VALUE);
+        list.add(Double.MIN_VALUE);
+        list.add(Json.createArrayBuilder().add("abc"));
+        list.add(Json.createObjectBuilder().add("one", 1));
+
+        JsonArray expected = Json.createArrayBuilder(list).build();
+
+        StringWriter sw = new StringWriter();
+        JsonWriter writer = Json.createWriter(sw);
+        writer.writeArray(expected);
+        writer.close();
+
+        JsonReader reader = Json.createReader(new StringReader(sw.toString()));
+        JsonArray actual = reader.readArray();
+        reader.close();
+
+        assertEquals(expected, actual);
+    }
+
     public void testStringValue() throws Exception {
         JsonArray array = Json.createArrayBuilder()
                 .add("John")
diff --git a/impl/src/test/java/org/glassfish/json/tests/JsonObjectTest.java b/impl/src/test/java/org/glassfish/json/tests/JsonObjectTest.java
index 9413d3e..a0ac06c 100644
--- a/impl/src/test/java/org/glassfish/json/tests/JsonObjectTest.java
+++ b/impl/src/test/java/org/glassfish/json/tests/JsonObjectTest.java
@@ -18,6 +18,11 @@
 
 import junit.framework.TestCase;
 
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
 import jakarta.json.*;
 
 /**
@@ -146,6 +151,61 @@
         }
     }
 
+    public void testObjectBuilderWithVariousValues() {
+        JsonObject expected = Json.createObjectBuilder()
+                .add("a", JsonValue.TRUE)
+                .add("b", JsonValue.FALSE)
+                .add("c", JsonValue.NULL)
+                .add("d", Integer.MAX_VALUE)
+                .add("e", Long.MAX_VALUE)
+                .add("f", Double.MAX_VALUE)
+                .add("g", Integer.MIN_VALUE)
+                .add("h", Long.MIN_VALUE)
+                .add("i", Double.MIN_VALUE)
+                .add("j", Json.createArrayBuilder().add("abc"))
+                .add("k", Json.createObjectBuilder().add("one", 1))
+                .build();
+
+        StringWriter sw = new StringWriter();
+        JsonWriter writer = Json.createWriter(sw);
+        writer.writeObject(expected);
+        writer.close();
+
+        JsonReader reader = Json.createReader(new StringReader(sw.toString()));
+        JsonObject actual = reader.readObject();
+        reader.close();
+
+        assertEquals(expected, actual);
+    }
+
+    public void testObjectBuilderWithMap() {
+        Map<String, Object> map = new HashMap<>();
+        map.put("a", JsonValue.TRUE);
+        map.put("b", JsonValue.FALSE);
+        map.put("c", JsonValue.NULL);
+        map.put("d", Integer.MAX_VALUE);
+        map.put("e", Long.MAX_VALUE);
+        map.put("f", Double.MAX_VALUE);
+        map.put("g", Integer.MIN_VALUE);
+        map.put("h", Long.MIN_VALUE);
+        map.put("i", Double.MIN_VALUE);
+        map.put("j", Json.createArrayBuilder().add("abc"));
+        map.put("k", Json.createObjectBuilder().add("one", 1));
+
+        JsonObject expected = Json.createObjectBuilder(map).build();
+
+        StringWriter sw = new StringWriter();
+        JsonWriter writer = Json.createWriter(sw);
+        writer.writeObject(expected);
+        writer.close();
+
+        JsonReader reader = Json.createReader(new StringReader(sw.toString()));
+        JsonObject actual = reader.readObject();
+        reader.close();
+
+        assertEquals(expected, actual);
+    }
+
     public void testObjectBuilderNpe() {
         try {
             JsonObject obj = Json.createObjectBuilder().add(null, 1).build();