diff --git a/CHANGELOG.md b/CHANGELOG.md index f636c8081..332a275ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 3.0.0 +Replace the dependency on org.json with a native kong.unirest library powered by gson. See the Upgrade Guide for details. + ## 2.4.00 (pending) * add an entire new return type: ```asBytes()``` (as well as async versions) will return a raw byte[] array. diff --git a/UPGRADE_GUIDE.md b/UPGRADE_GUIDE.md index 9707475fd..bef8ba257 100644 --- a/UPGRADE_GUIDE.md +++ b/UPGRADE_GUIDE.md @@ -1,14 +1,32 @@ +# Upgrade Guide + ## Upgrading to Unirest 3.0 -The primary difference in Unirest 3 is that the org.json dependency has been replaced by a clean-room implementation of the it's interface using Google Gson as the engine. This was done due to conflicts with the org.json license which requires that "The Software shall be used for Good, not Evil.". While many people would rightly view this as silly and unenforceable by law, many organizations such as Eclipse, Debian, and Apache will not allow linking to it. +The primary difference in Unirest 3 is that the org.json dependency has been replaced by a clean-room implementation of the it's interface using Google Gson as the engine. + +### What? Why? +This was done due to conflicts with the org.json license which requires that "The Software shall be used for Good, not Evil.". While many people would rightly view this as silly and unenforceable by law, many organizations such as Eclipse, Debian, and Apache will not allow using it. + +### Why not switch to the google implementation of org.json? +Several reasons: +* It has not been maintained in several years and no longer matches the org.json signatures. +* It causes classpath conflicts which many projects forbid. +* We would like Unirest to be able to expand beyond org.json and offer more advanced native features like object mapping. + +### Why Gson and not Jackson? +* Gson is closest in spirit and method signature to org.json and was deemed quicker to adopt. +* It's small, mature and a single dependency. +* It would conflict less in other projects than Jackson would which is both more popular and far more complex. + +### How was this done? +Implementation was done without looking at the internals of the org.json classes. This was accomplished by writing extensive unit tests in order to document behavior and method signatures and then simply changing the test to use this projects own classes as well as Google Gson. ### Differences between org.json and kong.unirest.json -For the most part kong.unirest.json honors all public interfaces and behavior of ```JSONArray``` and ```JSONObject```. The utility classes in org.json have NOT been implemented as they are not required for Unirest's use case. Implementation was done without looking at the internals of the org.json classes. This was accomplished by writing extensive unit tests in order to document behavior and method signatures and then simply changing the test to use this projects own classes as well as Google Gson. There are however differences: -* The namespace ```kong.unirest.json``` +* The namespace is now ```kong.unirest.json``` +* For the most part kong.unirest.json honors all public interfaces and behavior of ```JSONArray```, ```JSONObject```, and ```JSONPointer```. +* The utility classes in org.json have NOT been implemented as they are not required for Unirest's use case. So things like XML-to-JSON, and CSV-to-JSON have not been implemented. * Custom indenting with ```.toString(int spaces)``` does not honor the indent factor and always uses 2 spaces. Waiting on https://github.com/google/gson/pull/1280 for a fix. * There are some slight differences in the details of some error messages. -* ```optString``` and ```getString``` methods no longer throw an exception when the value is not a string but will simply convert the value to a string. -* when you ```put``` to a JSONArray org.json appears to store original object and only turns it to Json on serialization meaning you may also ```get``` it back. This library turns everything to a gson JsonElement immediately on ```put```. -* ```JSONPointer(List strings)``` has not been implemented. It's not documented and seems to assume knowledge of the internals of the class. + ## Upgrading to Unirest 2.0 from previous versions diff --git a/object-mapper-gson/src/test/java/kong/unirest/GsonObjectMapperTest.java b/object-mapper-gson/src/test/java/kong/unirest/GsonObjectMapperTest.java index e7039bf3a..39c975b62 100644 --- a/object-mapper-gson/src/test/java/kong/unirest/GsonObjectMapperTest.java +++ b/object-mapper-gson/src/test/java/kong/unirest/GsonObjectMapperTest.java @@ -61,7 +61,7 @@ public class GsonObjectMapperTest { private GsonObjectMapper om = new GsonObjectMapper(); @Test - public void canWrite() { + public void canWrite() throws Exception { TestMe test = new TestMe("foo", 42, new TestMe("bar", 666, null)); String json = om.writeValue(test); diff --git a/object-mapper-jackson/src/test/java/kong/unirest/JacksonObjectMapperTest.java b/object-mapper-jackson/src/test/java/kong/unirest/JacksonObjectMapperTest.java index 0c0697e99..4091e66e7 100644 --- a/object-mapper-jackson/src/test/java/kong/unirest/JacksonObjectMapperTest.java +++ b/object-mapper-jackson/src/test/java/kong/unirest/JacksonObjectMapperTest.java @@ -49,6 +49,7 @@ a copy of this software and associated documentation files (the */ package kong.unirest; +import org.json.JSONException; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; @@ -60,7 +61,7 @@ public class JacksonObjectMapperTest { private JacksonObjectMapper om = new JacksonObjectMapper(); @Test - public void canWrite() { + public void canWrite() throws JSONException { TestMe test = new TestMe("foo", 42, new TestMe("bar", 666, null)); String json = om.writeValue(test); diff --git a/unirest/pom.xml b/unirest/pom.xml index 7f9f4e00a..edcc2399a 100644 --- a/unirest/pom.xml +++ b/unirest/pom.xml @@ -42,11 +42,6 @@ - - org.json - json - 20180813 - junit junit diff --git a/unirest/src/main/java/kong/unirest/HttpRequestBody.java b/unirest/src/main/java/kong/unirest/HttpRequestBody.java index 7aa0003b3..5f6ab26dc 100644 --- a/unirest/src/main/java/kong/unirest/HttpRequestBody.java +++ b/unirest/src/main/java/kong/unirest/HttpRequestBody.java @@ -25,8 +25,8 @@ package kong.unirest; -import org.json.JSONArray; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; import java.io.File; import java.io.InputStream; diff --git a/unirest/src/main/java/kong/unirest/HttpRequestWithBody.java b/unirest/src/main/java/kong/unirest/HttpRequestWithBody.java index fb0103ef3..96180693d 100644 --- a/unirest/src/main/java/kong/unirest/HttpRequestWithBody.java +++ b/unirest/src/main/java/kong/unirest/HttpRequestWithBody.java @@ -25,8 +25,8 @@ package kong.unirest; -import org.json.JSONArray; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; import java.io.File; import java.io.InputStream; diff --git a/unirest/src/main/java/kong/unirest/JsonNode.java b/unirest/src/main/java/kong/unirest/JsonNode.java index 8ed927414..d4c7f7038 100644 --- a/unirest/src/main/java/kong/unirest/JsonNode.java +++ b/unirest/src/main/java/kong/unirest/JsonNode.java @@ -25,9 +25,9 @@ package kong.unirest; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONException; +import kong.unirest.json.JSONObject; public class JsonNode { diff --git a/unirest/src/main/java/kong/unirest/JsonPatch.java b/unirest/src/main/java/kong/unirest/JsonPatch.java index 8c74568ee..6a43b47f5 100644 --- a/unirest/src/main/java/kong/unirest/JsonPatch.java +++ b/unirest/src/main/java/kong/unirest/JsonPatch.java @@ -25,8 +25,8 @@ package kong.unirest; -import org.json.JSONArray; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; import java.util.ArrayList; import java.util.Collections; diff --git a/unirest/src/main/java/kong/unirest/JsonPatchItem.java b/unirest/src/main/java/kong/unirest/JsonPatchItem.java index 9484d0558..70b0fbd64 100644 --- a/unirest/src/main/java/kong/unirest/JsonPatchItem.java +++ b/unirest/src/main/java/kong/unirest/JsonPatchItem.java @@ -25,7 +25,7 @@ package kong.unirest; -import org.json.JSONObject; +import kong.unirest.json.JSONObject; import java.util.Objects; diff --git a/unirest/src/main/java/kong/unirest/json/JSONObject.java b/unirest/src/main/java/kong/unirest/json/JSONObject.java index 1bce077b8..59d7d7ab7 100644 --- a/unirest/src/main/java/kong/unirest/json/JSONObject.java +++ b/unirest/src/main/java/kong/unirest/json/JSONObject.java @@ -129,17 +129,21 @@ public static Object wrap(Object obj) { return new JSONArray((Collection)obj); } if(obj.getClass().isArray()){ - JSONArray array = new JSONArray(); - int length = Array.getLength(obj); - for (int i = 0; i < length; i ++) { - Object arrayElement = Array.get(obj, i); - array.put(arrayElement); - } - return array; + return wrapArray(obj); } return new JSONObject(); } + private static JSONArray wrapArray(Object obj) { + JSONArray array = new JSONArray(); + int length = Array.getLength(obj); + for (int i = 0; i < length; i ++) { + Object arrayElement = Array.get(obj, i); + array.put(arrayElement); + } + return array; + } + private static boolean isPrimitive(Object o){ return (o instanceof String || o instanceof Number @@ -831,8 +835,10 @@ public JSONObject put(String key, Object value) throws JSONException { put(key, (JSONObject) value); } else if (value instanceof Map){ put(key, (Map) value); - } else if (value instanceof Collection){ + } else if (value instanceof Collection) { put(key, (Collection) value); + } else if (value.getClass().isArray()){ + put(key, wrapArray(value)); } else { put(key, String.valueOf(value)); } diff --git a/unirest/src/main/java/kong/unirest/json/JSONPointer.java b/unirest/src/main/java/kong/unirest/json/JSONPointer.java index 0ac35ae2c..f16038c1a 100644 --- a/unirest/src/main/java/kong/unirest/json/JSONPointer.java +++ b/unirest/src/main/java/kong/unirest/json/JSONPointer.java @@ -32,6 +32,7 @@ /** * A Json Pointer query object following * https://tools.ietf.org/html/rfc6901 + * */ public class JSONPointer { @@ -103,6 +104,12 @@ private static JSONPointer createPointer(String query) { return compileNext(query); } + /** + * Many of the path compiling code was borrowed from Jackson. + * It is, slightly modified but similar enough to give credit. + * please see com.fasterxml.jackson.core.JsonPointer + * @author Tatu Saloranta + */ private static JSONPointer compileNext(String query) { final int end = query.length(); for (int i = 1; i < end; ) { diff --git a/unirest/src/test/java/BehaviorTests/AsJsonTest.java b/unirest/src/test/java/BehaviorTests/AsJsonTest.java index de1f9801e..f20289f94 100644 --- a/unirest/src/test/java/BehaviorTests/AsJsonTest.java +++ b/unirest/src/test/java/BehaviorTests/AsJsonTest.java @@ -81,7 +81,7 @@ public void failureToReturnValidJsonWillResultInAnEmptyNode() { assertNull(response.getBody()); UnirestParsingException ex = response.getParsingError().get(); assertEquals("You did something bad", ex.getOriginalBody()); - assertEquals("org.json.JSONException: A JSONArray text must start with '[' at 1 [character 2 line 1]", + assertEquals("kong.unirest.json.JSONException: Invalid JSON", response.getParsingError().get().getMessage()); } @@ -93,7 +93,7 @@ public void failureToReturnValidJsonWillResultInAnEmptyNodeAsync() { assertEquals(400, response.getStatus()); assertNull(response.getBody()); assertEquals(null, response.getBody()); - assertEquals("org.json.JSONException: A JSONArray text must start with '[' at 1 [character 2 line 1]", + assertEquals("kong.unirest.json.JSONException: Invalid JSON", response.getParsingError().get().getMessage()); })); diff --git a/unirest/src/test/java/BehaviorTests/DefectTest.java b/unirest/src/test/java/BehaviorTests/DefectTest.java index ad2d80c6d..b762fb56f 100644 --- a/unirest/src/test/java/BehaviorTests/DefectTest.java +++ b/unirest/src/test/java/BehaviorTests/DefectTest.java @@ -27,7 +27,7 @@ import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; import org.apache.http.nio.client.HttpAsyncClient; -import org.json.JSONObject; +import kong.unirest.json.JSONObject; import org.junit.Ignore; import kong.unirest.Unirest; import org.junit.Test; diff --git a/unirest/src/test/java/BehaviorTests/JsonPatchTest.java b/unirest/src/test/java/BehaviorTests/JsonPatchTest.java index eee4e32cb..4abfe6eed 100644 --- a/unirest/src/test/java/BehaviorTests/JsonPatchTest.java +++ b/unirest/src/test/java/BehaviorTests/JsonPatchTest.java @@ -27,8 +27,8 @@ import com.google.common.collect.ImmutableMap; import kong.unirest.Unirest; -import org.json.JSONArray; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; import kong.unirest.TestUtil; @@ -141,7 +141,7 @@ public void canCopyObjects() { } @Test - public void thatsSomeValidJson() throws IOException { + public void thatsSomeValidJson() throws Exception { String patch = Unirest.jsonPatch(MockServer.PATCH) .add("/fruits/-", "Apple") .remove("/bugs") diff --git a/unirest/src/test/java/BehaviorTests/UniBodyPostingTest.java b/unirest/src/test/java/BehaviorTests/UniBodyPostingTest.java index 91f3a9052..a6625dcc3 100644 --- a/unirest/src/test/java/BehaviorTests/UniBodyPostingTest.java +++ b/unirest/src/test/java/BehaviorTests/UniBodyPostingTest.java @@ -29,8 +29,8 @@ import kong.unirest.MockCallback; import kong.unirest.Unirest; import kong.unirest.UnirestConfigException; -import org.json.JSONArray; -import org.json.JSONObject; +import kong.unirest.json.JSONArray; +import kong.unirest.json.JSONObject; import org.junit.Test; import java.nio.charset.StandardCharsets; diff --git a/unirest/src/test/java/kong/unirest/JacksonObjectMapper.java b/unirest/src/test/java/kong/unirest/JacksonObjectMapper.java index 7f7e563bf..97ad37a16 100644 --- a/unirest/src/test/java/kong/unirest/JacksonObjectMapper.java +++ b/unirest/src/test/java/kong/unirest/JacksonObjectMapper.java @@ -35,7 +35,7 @@ import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.datatype.guava.GuavaModule; -import org.json.JSONObject; +import kong.unirest.json.JSONObject; import java.io.File; import java.io.IOException; diff --git a/unirest/src/test/java/kong/unirest/JacksonObjectMapperTest.java b/unirest/src/test/java/kong/unirest/JacksonObjectMapperTest.java index 0b8ef4401..736e1c771 100644 --- a/unirest/src/test/java/kong/unirest/JacksonObjectMapperTest.java +++ b/unirest/src/test/java/kong/unirest/JacksonObjectMapperTest.java @@ -26,6 +26,7 @@ package kong.unirest; import BehaviorTests.RequestCapture; +import org.json.JSONException; import org.junit.Test; import org.skyscreamer.jsonassert.JSONAssert; @@ -34,7 +35,7 @@ public class JacksonObjectMapperTest { private JacksonObjectMapper om = new JacksonObjectMapper(); @Test - public void jsonPatch() { + public void jsonPatch() throws JSONException { JsonPatch patch = new JsonPatch(); patch.add("/foo", "bar"); patch.add("/baz", "qux"); @@ -48,7 +49,7 @@ public void jsonPatch() { } @Test - public void jsonPatchInRequestCapture() { + public void jsonPatchInRequestCapture() throws JSONException { JsonPatch patch = new JsonPatch(); patch.add("/foo", "bar"); patch.add("/baz", "qux"); diff --git a/unirest/src/test/java/kong/unirest/json/JSONArrayTest.java b/unirest/src/test/java/kong/unirest/json/JSONArrayTest.java index 96f8c90df..3aaf4025c 100644 --- a/unirest/src/test/java/kong/unirest/json/JSONArrayTest.java +++ b/unirest/src/test/java/kong/unirest/json/JSONArrayTest.java @@ -260,7 +260,7 @@ public void strings() { } @Test - public void jsonObjects() { + public void jsonObjects() throws Exception { JSONObject subObj = new JSONObject("{\"derp\": 42}"); JSONArray obj = new JSONArray(); assertSame(obj, obj.put(subObj)); @@ -274,7 +274,7 @@ public void jsonObjects() { } @Test - public void jsonArrays() { + public void jsonArrays() throws Exception { JSONArray subObj = new JSONArray("[42]"); JSONArray obj = new JSONArray(); assertSame(obj, obj.put(subObj)); diff --git a/unirest/src/test/java/kong/unirest/json/JSONObjectTest.java b/unirest/src/test/java/kong/unirest/json/JSONObjectTest.java index a55b0fb81..df03d5a45 100644 --- a/unirest/src/test/java/kong/unirest/json/JSONObjectTest.java +++ b/unirest/src/test/java/kong/unirest/json/JSONObjectTest.java @@ -223,7 +223,7 @@ public void strings() { } @Test - public void jsonObjects() { + public void jsonObjects() throws Exception { JSONObject subObj = new JSONObject("{\"derp\": 42}"); JSONObject obj = new JSONObject(); obj.put("key", subObj); @@ -238,7 +238,7 @@ public void jsonObjects() { } @Test - public void jsonArrays() { + public void jsonArrays() throws Exception { JSONArray subObj = new JSONArray("[42]"); JSONObject obj = new JSONObject(); obj.put("key", subObj); @@ -591,7 +591,7 @@ public static void assertJSONEx(TestUtil.ExRunnable exRunnable, String message) assertException(exRunnable, JSONException.class, message); } - public static void assertEqualJson(Object subObj, Object value) { + public static void assertEqualJson(Object subObj, Object value) throws org.json.JSONException { JSONAssert.assertEquals(subObj.toString(), value.toString(), true); } diff --git a/unirest/src/test/java/kong/unirest/json/JSONPointerTest.java b/unirest/src/test/java/kong/unirest/json/JSONPointerTest.java index c3990956c..b170e230f 100644 --- a/unirest/src/test/java/kong/unirest/json/JSONPointerTest.java +++ b/unirest/src/test/java/kong/unirest/json/JSONPointerTest.java @@ -89,12 +89,12 @@ public void elementInObjectDoesNotExist() { } @Test - public void testRef_all() { + public void testRef_all() throws Exception { assertQueryJson(RFC_TEST, ""); } @Test - public void testRef_Array(){ + public void testRef_Array() throws Exception { assertQueryJson("[\"bar\", \"baz\"]", "/foo"); } @@ -167,7 +167,7 @@ public void builder(){ pointer.toString()); } - private void assertQueryJson(String s, String s2) { + private void assertQueryJson(String s, String s2) throws Exception { JSONAssert.assertEquals(s, obj.query(s2).toString(), true); }