diff --git a/README.md b/README.md
index 9914dab..8fa588e 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,8 @@ in the Android SDK. As we all know, those stock classes tend to be a pain. They
1. [Dependency](https://github.com/afollestad/ason#dependency)
1. [Gradle (Java)](https://github.com/afollestad/ason#gradle-java)
2. [Gradle (Android)](https://github.com/afollestad/ason#gradle-android)
- 3. [Maven](https://github.com/afollestad/ason#maven)
+ 3. [Gradle (Kotlin)](https://github.com/afollestad/ason#gradle-kotlin)
+ 4. [Maven](https://github.com/afollestad/ason#maven)
2. [Parsing and Building Objects](https://github.com/afollestad/ason#parsing-and-building-objects)
3. [Retrieving Values from Objects](https://github.com/afollestad/ason#retrieving-values-from-objects)
4. [Parsing and Building Arrays](https://github.com/afollestad/ason#parsing-and-building-arrays)
@@ -52,7 +53,7 @@ The dependency is available via jCenter.
```Gradle
dependencies {
...
- compile 'com.afollestad:ason:1.3.1'
+ compile 'com.afollestad:ason:1.4.0'
}
```
@@ -63,9 +64,22 @@ Since Android includes `org.json` classes, you'll want to exclude the copies pro
```Gradle
dependencies {
...
- compile('com.afollestad:ason:1.3.1') {
+ compile('com.afollestad:ason:1.4.0') {
exclude group: 'org.json', module: 'json'
- // exclude group: 'com.intellij', module: 'annotations' - Enable this, if you use Kotlin, otherwise you may get a DexException
+ }
+}
+```
+
+### Gradle (Kotlin)
+
+In Kotlin, you'll want to exclude IntelliJ's annotations library to avoid a DexException. *If you are using Kotlin with
+Android, make sure you also exclude org.json as shown in the section above.*
+
+```Gradle
+dependencies {
+ ...
+ compile('com.afollestad:ason:1.4.0') {
+ exclude group: 'com.intellij', module: 'annotations'
}
}
```
@@ -76,7 +90,7 @@ dependencies {
com.afollestad
ason
- 1.3.1
+ 1.4.0
pom
```
@@ -288,13 +302,24 @@ int day = ason.get("birthday.day");
int year = ason.get("birthday.year");
```
-You can do the same on arrays, but you need to specify the index of the object to pull from too:
+If you wanted to remove the inner "year" value:
+
+```java
+Ason ason = // ...
+ason.remove("birthday.year");
+```
+
+---
+
+You can use dot notation with arrays too, but you need to specify the index of the object to pull from:
```java
AsonArray ason = // ...
String name = ason.get(1, "birthday.month");
```
+---
+
As a bonus, you can check equality without doing a manual value comparison:
```java
@@ -305,22 +330,6 @@ AsonArray ason2 = // ...
boolean birthYearCheck2 = ason2.equal(2, "birthday.year", 1995);
```
-And arrays:
-
-```java
-Ason ason = new Ason()
- .put("id", 1)
- .put("name", "Aidan")
- .put("birthday.month", "July")
- .put("birthday.day", 28)
- .put("birthday.year", 1995);
-AsonArray array = AsonArray();
-array.put(ason);
-
-// The first parameter is the index of the item, the second is a key path, the third is the value you're comparing to
-boolean firstItemBirthYearCheck = array.equal(0, "birthday.year", 1995);
-```
-
### Index Notation
To extend on dot notations in paths, you can use this notation to perform operations on array children.
@@ -344,6 +353,23 @@ Take this JSON:
}
```
+You could create this using index notation as such:
+
+```java
+Ason ason = new Ason()
+ .put("group_id", 1)
+ .put("title", "Hello, world!")
+ .put("participants.$0.name", "Aidan")
+ .put("participants.$0.id", 2)
+ .put("participants.$1.name", "Waverly")
+ .put("participants.$1.id", 1);
+```
+
+The dollar sign followed by the number 0 indicates that you want the item at index 0 (position 1)
+within an array called "participants".
+
+---
+
You can retrieve the value of "name" in the second participant like this:
```java
@@ -351,8 +377,13 @@ Ason object = // ...
String name = object.get("participants.$1.name");
```
-The dollar sign followed by the number 1 indicates that you want the item at index 1 (position 2)
-within the array called "participants".
+If you wanted to remove the first item from the inner array, you can do that with index notation. This avoids the
+need to first retrieve the "participants" object:
+
+```java
+Ason object = // ...
+object.remove("participants.$0");
+```
### Escaping Periods and Dollar Signs
diff --git a/build.gradle b/build.gradle
index 4627ac4..2ba85d0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,5 +1,5 @@
group 'com.afollestad'
-version '1.3.1'
+version '1.4.0'
apply plugin: 'java'
apply plugin: 'idea'
@@ -32,7 +32,7 @@ publish {
userOrg = 'drummer-aidan'
groupId = 'com.afollestad'
artifactId = 'ason'
- publishVersion = '1.3.1'
+ publishVersion = '1.4.0'
website = 'https://github.com/afollestad/ason'
}
diff --git a/src/main/java/com/afollestad/ason/Ason.java b/src/main/java/com/afollestad/ason/Ason.java
index b6f9449..9588a7f 100644
--- a/src/main/java/com/afollestad/ason/Ason.java
+++ b/src/main/java/com/afollestad/ason/Ason.java
@@ -95,8 +95,19 @@ public Ason put(@NotNull String key, Object... values) {
}
if (key.contains(".")) {
final String[] splitKey = splitPath(key);
- JSONObject target = followPath(json, key, splitKey, true);
- target.put(splitKey[splitKey.length - 1], insertObject);
+ Object target = followPath(json, key, splitKey, true);
+ if (target instanceof JSONArray) {
+ JSONArray arrayTarget = (JSONArray) target;
+ String indexKey = splitKey[splitKey.length - 1].substring(1);
+ int insertIndex = Integer.parseInt(indexKey);
+ if (insertIndex > arrayTarget.length() - 1) {
+ arrayTarget.put(insertObject);
+ } else {
+ arrayTarget.put(insertIndex, insertObject);
+ }
+ } else {
+ ((JSONObject) target).put(splitKey[splitKey.length - 1], insertObject);
+ }
} else {
putInternal(null, null, key, insertObject);
}
@@ -104,7 +115,19 @@ public Ason put(@NotNull String key, Object... values) {
}
public Ason remove(@NotNull String key) {
- json.remove(key);
+ String[] splitKey = splitPath(key);
+ if (splitKey.length == 1) {
+ json.remove(key);
+ } else {
+ Object followed = followPath(json, key, splitKey, false);
+ if (followed instanceof JSONArray) {
+ JSONArray followedArray = (JSONArray) followed;
+ int insertIndex = Integer.parseInt(splitKey[splitKey.length - 1].substring(1));
+ followedArray.remove(insertIndex);
+ } else {
+ ((JSONObject) followed).remove(splitKey[splitKey.length - 1]);
+ }
+ }
return this;
}
diff --git a/src/main/java/com/afollestad/ason/Util.java b/src/main/java/com/afollestad/ason/Util.java
index f5bb89f..829202e 100644
--- a/src/main/java/com/afollestad/ason/Util.java
+++ b/src/main/java/com/afollestad/ason/Util.java
@@ -1,5 +1,6 @@
package com.afollestad.ason;
+import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -35,7 +36,7 @@ static String[] splitPath(String key) {
return result.toArray(new String[result.size()]);
}
- private static boolean isNumber(String string) {
+ static boolean isNumber(String string) {
for (char c : string.toCharArray()) {
if (!Character.isDigit(c)) {
return false;
@@ -44,10 +45,11 @@ private static boolean isNumber(String string) {
return true;
}
- static JSONObject followPath(JSONObject wrapper,
- String key,
- String[] splitKey,
- boolean createMissing) {
+ @NotNull static Object followPath(
+ JSONObject wrapper,
+ String key,
+ String[] splitKey,
+ boolean createMissing) {
// Get value for the first path key
Object parent = wrapper.opt(splitKey[0]);
if (parent != null
@@ -58,7 +60,13 @@ static JSONObject followPath(JSONObject wrapper,
parent.getClass().getName() + ").");
} else if (parent == null) {
if (createMissing) {
- parent = new JSONObject();
+ if (splitKey[0].startsWith("$")
+ || (splitKey.length > 1
+ && splitKey[1].startsWith("$"))) {
+ parent = new JSONArray();
+ } else {
+ parent = new JSONObject();
+ }
wrapper.put(splitKey[0], parent);
} else {
throw new InvalidPathException("No object or array found for the first component of key " +
@@ -85,8 +93,14 @@ static JSONObject followPath(JSONObject wrapper,
current.getClass().getName() + ").");
} else if (current == null) {
if (createMissing) {
- current = new JSONObject();
- ((JSONObject) parent).put(currentKey, current);
+ if (i < splitKey.length - 1
+ && splitKey[i + 1].startsWith("$")) {
+ current = new JSONArray();
+ ((JSONArray) parent).put(current);
+ } else {
+ current = new JSONObject();
+ ((JSONArray) parent).put(current);
+ }
} else {
throw new NullPathException("Item at index " + i + " " +
"of current entry refers to a null or out of bounds entry.");
@@ -107,7 +121,12 @@ static JSONObject followPath(JSONObject wrapper,
current.getClass().getName() + ").");
} else if (current == null) {
if (createMissing) {
- current = new JSONObject();
+ if (i < splitKey.length - 1
+ && splitKey[i + 1].startsWith("$")) {
+ current = new JSONArray();
+ } else {
+ current = new JSONObject();
+ }
((JSONObject) parent).put(currentKey, current);
} else {
throw new NullPathException("Item at index " + i + " " +
@@ -117,7 +136,7 @@ static JSONObject followPath(JSONObject wrapper,
parent = current;
}
- return (JSONObject) parent;
+ return parent;
}
@SuppressWarnings("unchecked") static T getPathValue(
@@ -127,8 +146,12 @@ static JSONObject followPath(JSONObject wrapper,
if (splitKey.length == 1) {
return (T) wrapper.get(key);
}
- JSONObject target = followPath(wrapper, key, splitKey, false);
- return (T) target.opt(splitKey[splitKey.length - 1]);
+ Object target = followPath(wrapper, key, splitKey, false);
+ if (target instanceof JSONObject) {
+ return (T) ((JSONObject) target).opt(splitKey[splitKey.length - 1]);
+ } else {
+ throw new InvalidPathException("Cannot get a value from a JSONArray using a key.");
+ }
}
@SuppressWarnings("unchecked")
diff --git a/src/test/java/com/afollestad/ason/AsonPathTest.java b/src/test/java/com/afollestad/ason/AsonPathTest.java
index f5c06c5..bf73938 100644
--- a/src/test/java/com/afollestad/ason/AsonPathTest.java
+++ b/src/test/java/com/afollestad/ason/AsonPathTest.java
@@ -7,6 +7,11 @@
public class AsonPathTest {
+ @Test public void test_split_path_no_components() {
+ String[] result = Util.splitPath("Hello!");
+ assertEquals(1, result.length);
+ }
+
@Test public void builder_test() {
Ason ason = new Ason()
.put("person._id", 3)
@@ -21,6 +26,69 @@ public class AsonPathTest {
assertEquals(output, ason.toString());
}
+ @Test public void builder_index_test_one() {
+ Ason ason = new Ason()
+ .put("_id", 3)
+ .put("name", "Aidan")
+ .put("pets.$0", "Kierra")
+ .put("pets.$1", "Elijah")
+ .put("pets.$2", "Olivia");
+ assertEquals("{\"pets\":" +
+ "[\"Kierra\",\"Elijah\",\"Olivia\"]," +
+ "\"name\":\"Aidan\",\"_id\":3}", ason.toString());
+ }
+
+ @Test public void builder_index_test_two() {
+ Ason ason = new Ason()
+ .put("_id", 3)
+ .put("name", "Aidan")
+ .put("pets.$0.id", 1)
+ .put("pets.$0.name", "Kierra")
+ .put("pets.$1.id", 2)
+ .put("pets.$1.name", "Elijah")
+ .put("pets.$2.id", 3)
+ .put("pets.$2.name", "Olivia");
+ assertEquals("{\"pets\":[" +
+ "{\"name\":\"Kierra\",\"id\":1}," +
+ "{\"name\":\"Elijah\",\"id\":2}," +
+ "{\"name\":\"Olivia\",\"id\":3}]," +
+ "\"name\":\"Aidan\",\"_id\":3}", ason.toString());
+ }
+
+ @Test public void builder_index_test_three() {
+ Ason ason = new Ason()
+ .put("_id", 1)
+ .put("people.$0.name", "Aidan")
+ .put("people.$0.pets.$0", "Kierra")
+ .put("people.$0.pets.$1", "Elijah")
+ .put("people.$0.pets.$2", "Olivia");
+ assertEquals("{\"_id\":1," +
+ "\"people\":[" +
+ "{\"pets\":" +
+ "[\"Kierra\",\"Elijah\",\"Olivia\"]," +
+ "\"name\":\"Aidan\"}" +
+ "]" +
+ "}", ason.toString());
+ }
+
+ @Test public void builder_index_test_four() {
+ Ason ason = new Ason()
+ .put("_id", 1)
+ .put("people.$0.name", "Aidan")
+ .put("people.$0.id", 1)
+ .put("people.$0.pets.$0.name", "Kierra")
+ .put("people.$0.pets.$0.id", 1)
+ .put("people.$0.pets.$1.name", "Elijah")
+ .put("people.$0.pets.$1.id", 2);
+ assertEquals("{\"_id\":1," +
+ "\"people\":[" +
+ "{\"pets\":" +
+ "[{\"name\":\"Kierra\",\"id\":1}," +
+ "{\"name\":\"Elijah\",\"id\":2}]," +
+ "\"name\":\"Aidan\"," +
+ "\"id\":1}]}", ason.toString());
+ }
+
@Test public void from_string_test() {
String input = "{\"person\":{\"name\":\"Aidan\",\"_id\":3,\"age\":21}}";
Ason ason = new Ason(input);
@@ -78,4 +146,29 @@ public class AsonPathTest {
Ason object = new Ason(input);
assertEquals("Waverly", object.get("participants.\\$1.name"));
}
+
+ @Test public void test_remove_dot_notation() {
+ Ason ason = new Ason()
+ .put("_id", 3)
+ .put("name", "Aidan")
+ .put("age", 21)
+ .put("spouse.name", "Waverly")
+ .put("spouse.age", 19);
+ ason.remove("spouse.age");
+ assertEquals("{\"name\":\"Aidan\",\"_id\":3,\"age\":21," +
+ "\"spouse\":{\"name\":\"Waverly\"}}", ason.toString());
+ }
+
+ @Test public void test_remove_index_notation() {
+ String input = "{\"group_id\":1,\"title\":\"Hello, world!\"," +
+ "\"participants\":[{\"name\":\"Aidan\",\"id\":2}," +
+ "{\"name\":\"Waverly\",\"id\":1}]}";
+ Ason object = new Ason(input);
+ object.remove("participants.$0");
+
+ AsonArray participants = object.get("participants");
+ assertEquals(participants.size(), 1);
+ assertEquals(participants.get(0).get("id"), 1);
+ assertEquals(participants.get(0).get("name"), "Waverly");
+ }
}
diff --git a/src/test/java/com/afollestad/ason/AsonTest.java b/src/test/java/com/afollestad/ason/AsonTest.java
index 986f855..0226bb1 100644
--- a/src/test/java/com/afollestad/ason/AsonTest.java
+++ b/src/test/java/com/afollestad/ason/AsonTest.java
@@ -5,6 +5,7 @@
import java.util.HashMap;
import java.util.Map;
+import static com.afollestad.ason.Util.isNumber;
import static org.junit.Assert.*;
public class AsonTest {
@@ -17,6 +18,17 @@ public class AsonTest {
}
}
+ @Test public void test_is_number_true() {
+ assertTrue(isNumber("1234"));
+ assertTrue(isNumber("67891023231"));
+ }
+
+ @Test public void test_is_number_false() {
+ assertFalse(isNumber("hi"));
+ assertFalse(isNumber("@1234"));
+ assertFalse(isNumber("1234!%"));
+ }
+
@Test public void builder_test() {
Ason ason = new Ason()
.put("_id", 3)
@@ -47,7 +59,7 @@ public class AsonTest {
@Test public void test_is_null() {
Ason ason = new Ason()
.put("_id", 3)
- .put("name", null)
+ .put("name", (Object[]) null)
.put("age", 21);
assertTrue(ason.isNull("name"));
assertFalse(ason.isNull("age"));