Skip to content

Commit 988d443

Browse files
committed
Add BoxJSONObject class
This class helps encoding and decoding JSON. It also tracks local changes to an object until they can be sent back to the Box API.
1 parent 8861fe3 commit 988d443

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package com.box.sdk;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
import com.eclipsesource.json.JsonObject;
7+
import com.eclipsesource.json.JsonValue;
8+
9+
/**
10+
* The abstract base class for all types that contain JSON data returned by the Box API. The most common implementation
11+
* of BoxJSONObject is {@link BoxResource.Info} and its subclasses. Changes made to a BoxJSONObject will be tracked
12+
* locally until the pending changes are sent back to Box in order to avoid unnecessary network requests.
13+
*
14+
*/
15+
public abstract class BoxJSONObject {
16+
/**
17+
* The JsonObject that contains any local pending changes. When getPendingChanges is called, this object will be
18+
* encoded to a JSON string.
19+
*/
20+
private JsonObject pendingChanges;
21+
22+
/**
23+
* A map of other BoxJSONObjects which will be lazily converted to a JsonObject once getPendingChanges is called.
24+
* This allows changes to be made to a child BoxJSONObject and still have those changes reflected in the JSON
25+
* string.
26+
*/
27+
private Map<String, BoxJSONObject> lazyPendingChanges;
28+
29+
/**
30+
* Constructs an empty BoxJSONObject.
31+
*/
32+
public BoxJSONObject() {
33+
this.lazyPendingChanges = new HashMap<String, BoxJSONObject>();
34+
}
35+
36+
/**
37+
* Constructs a BoxJSONObject by decoding it from a JSON string.
38+
* @param json the JSON string to decode.
39+
*/
40+
public BoxJSONObject(String json) {
41+
this(JsonObject.readFrom(json));
42+
}
43+
44+
/**
45+
* Constructs a BoxJSONObject using an already parsed JSON object.
46+
* @param jsonObject the parsed JSON object.
47+
*/
48+
BoxJSONObject(JsonObject jsonObject) {
49+
this();
50+
51+
this.update(jsonObject);
52+
}
53+
54+
/**
55+
* Clears any pending changes from this JSON object.
56+
*/
57+
public void clearPendingChanges() {
58+
this.pendingChanges = null;
59+
this.lazyPendingChanges.clear();
60+
}
61+
62+
/**
63+
* Gets a JSON string containing any pending changes to this object that can be sent back to the Box API.
64+
* @return a JSON string containing the pending changes.
65+
*/
66+
public String getPendingChanges() {
67+
JsonObject jsonObject = this.getPendingJSONObject();
68+
if (jsonObject == null) {
69+
return null;
70+
}
71+
72+
return jsonObject.toString();
73+
}
74+
75+
/**
76+
* Invoked with a JSON member whenever this object is updated or created from a JSON object.
77+
*
78+
* <p>Subclasses should override this method in order to parse any JSON members it knows about. This method is a
79+
* no-op by default.</p>
80+
*
81+
* @param member the JSON member to be parsed.
82+
*/
83+
void parseJSONMember(JsonObject.Member member) { }
84+
85+
/**
86+
* Adds a pending field change that needs to be sent to the API. It will be included in the JSON string the next
87+
* time {@link #getPendingChanges} is called.
88+
* @param key the name of the field.
89+
* @param value the new boolean value of the field.
90+
*/
91+
void addPendingChange(String key, boolean value) {
92+
if (this.pendingChanges == null) {
93+
this.pendingChanges = new JsonObject();
94+
}
95+
96+
this.pendingChanges.set(key, value);
97+
}
98+
99+
/**
100+
* Adds a pending field change that needs to be sent to the API. It will be included in the JSON string the next
101+
* time {@link #getPendingChanges} is called.
102+
* @param key the name of the field.
103+
* @param value the new String value of the field.
104+
*/
105+
void addPendingChange(String key, String value) {
106+
this.addPendingChange(key, JsonValue.valueOf(value));
107+
}
108+
109+
/**
110+
* Adds a pending field change that needs to be sent to the API. It will be included in the JSON string the next
111+
* time {@link #getPendingChanges} is called.
112+
* @param key the name of the field.
113+
* @param value the new BoxJSONObject value of the field.
114+
*/
115+
void addPendingChange(String key, BoxJSONObject value) {
116+
this.lazyPendingChanges.put(key, value);
117+
}
118+
119+
/**
120+
* Adds a pending field change that needs to be sent to the API. It will be included in the JSON string the next
121+
* time {@link #getPendingChanges} is called.
122+
* @param key the name of the field.
123+
* @param value the JsonValue of the field.
124+
*/
125+
private void addPendingChange(String key, JsonValue value) {
126+
if (this.pendingChanges == null) {
127+
this.pendingChanges = new JsonObject();
128+
}
129+
130+
this.pendingChanges.set(key, value);
131+
}
132+
133+
/**
134+
* Updates this BoxJSONObject using the information in a JSON object.
135+
* @param jsonObject the JSON object containing updated information.
136+
*/
137+
void update(JsonObject jsonObject) {
138+
for (JsonObject.Member member : jsonObject) {
139+
if (member.getValue().isNull()) {
140+
continue;
141+
}
142+
143+
this.parseJSONMember(member);
144+
}
145+
146+
this.clearPendingChanges();
147+
}
148+
149+
/**
150+
* Gets a JsonObject containing any pending changes to this object that can be sent back to the Box API.
151+
* @return a JsonObject containing the pending changes.
152+
*/
153+
JsonObject getPendingJSONObject() {
154+
if (this.pendingChanges == null && !this.lazyPendingChanges.isEmpty()) {
155+
this.pendingChanges = new JsonObject();
156+
}
157+
158+
for (Map.Entry<String, BoxJSONObject> entry : this.lazyPendingChanges.entrySet()) {
159+
this.pendingChanges.set(entry.getKey(), entry.getValue().getPendingJSONObject());
160+
}
161+
return this.pendingChanges;
162+
}
163+
}

0 commit comments

Comments
 (0)