Skip to content

Commit 1b36e00

Browse files
committed
hard change on update methods for better memory usage
1 parent 0e84420 commit 1b36e00

File tree

2 files changed

+219
-286
lines changed

2 files changed

+219
-286
lines changed

src/main/java/org/json/JSONObject.java

Lines changed: 42 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package org.json;
22

3-
import java.beans.PropertyChangeListener;
4-
import java.beans.PropertyChangeSupport;
53
import java.io.Closeable;
64

75
/*
@@ -38,7 +36,6 @@ of this software and associated documentation files (the "Software"), to deal
3836
import java.lang.reflect.Modifier;
3937
import java.math.BigDecimal;
4038
import java.math.BigInteger;
41-
import java.util.ArrayList;
4239
import java.util.Collection;
4340
import java.util.Enumeration;
4441
import java.util.HashMap;
@@ -48,6 +45,7 @@ of this software and associated documentation files (the "Software"), to deal
4845
import java.util.Objects;
4946
import java.util.ResourceBundle;
5047
import java.util.Set;
48+
import java.util.concurrent.atomic.AtomicBoolean;
5149
import java.util.regex.Pattern;
5250

5351
/**
@@ -1793,9 +1791,7 @@ public JSONObject putMap(String key, Map<?, ?> value) throws JSONException {
17931791
return this.put(key, new JSONObject(value));
17941792
}
17951793

1796-
private PropertyChangeSupport propertyChangeSupportUpdate = new PropertyChangeSupport(this);
1797-
private PropertyChangeSupport propertyChangeSupportNotify = new PropertyChangeSupport(this);
1798-
private static final String propertyChangeGlobalKeyword = "__THIS__";
1794+
private Runnable updateListener = null;
17991795
/**
18001796
* Add a PropertyChangeListener to the JSONObject.
18011797
* The listener object may be added more than once, and will be called
@@ -1805,32 +1801,8 @@ public JSONObject putMap(String key, Map<?, ?> value) throws JSONException {
18051801
*
18061802
* @param listener The PropertyChangeListener to be added
18071803
*/
1808-
public void onUpdateGlobal(PropertyChangeListener listener) {
1809-
this.propertyChangeSupportUpdate.addPropertyChangeListener(JSONObject.propertyChangeGlobalKeyword, listener);
1810-
}
1811-
1812-
/**
1813-
* Add a PropertyChangeListener for a specific property to the JSONObject.
1814-
* The listener will be invoked only when a call on
1815-
* update names that specific property
1816-
* The listener object may be added more than once, and will be called
1817-
* as many times as it is added.
1818-
* If {@code listener} is null, no exception is thrown and no action
1819-
* is taken.
1820-
*
1821-
* @param key The key string to listen on.
1822-
* @param listener The PropertyChangeListener to be added
1823-
*/
1824-
public void onUpdate(String key, PropertyChangeListener listener) {
1825-
if (JSONObject.propertyChangeGlobalKeyword.equals(key)) {
1826-
throw new JSONException("key \"" + JSONObject.propertyChangeGlobalKeyword + "\" is reserved");
1827-
} else {
1828-
this.propertyChangeSupportUpdate.addPropertyChangeListener(key, listener);
1829-
}
1830-
}
1831-
1832-
public void onNotify(String key, PropertyChangeListener listener) {
1833-
this.propertyChangeSupportNotify.addPropertyChangeListener(key, listener);
1804+
public void onUpdate(Runnable runnable) throws JSONException {
1805+
updateListener = runnable;
18341806
}
18351807

18361808
/**
@@ -1839,7 +1811,7 @@ public void onNotify(String key, PropertyChangeListener listener) {
18391811
*
18401812
* @param key
18411813
* A key string.
1842-
* @param newValue
1814+
* @param v2
18431815
* An object which is the newValue. It should be of one of these
18441816
* types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
18451817
* String, or the JSONObject.NULL object.
@@ -1849,60 +1821,38 @@ public void onNotify(String key, PropertyChangeListener listener) {
18491821
* @throws JSONException
18501822
* If updateListener not initialized.
18511823
*/
1852-
public JSONObject update(String key, Object newValue) throws JSONException {
1853-
final JSONObject oldThis = new JSONObject(this.toString());
1854-
final Object oldValue = this.opt(key);
1855-
1856-
1857-
if (newValue instanceof JSONObject) {
1858-
this.put(key, newValue);
1859-
final JSONObject __oldThis = new JSONObject(this.toString());
1860-
1861-
JSONObject newValueJson = (JSONObject) newValue;
1862-
1863-
newValueJson.onUpdateGlobal(evt -> {
1864-
this.propertyChangeSupportUpdate.firePropertyChange(JSONObject.propertyChangeGlobalKeyword, __oldThis, this);
1865-
this.propertyChangeSupportUpdate.firePropertyChange(key, oldValue, newValue);
1866-
1867-
this.propertyChangeSupportNotify.firePropertyChange(key, oldValue, newValue);
1868-
});
1869-
} else {
1870-
this.put(key, newValue);
1824+
public JSONObject update(String key, Object v2) throws JSONException {
1825+
final Object v1 = super.put(key, v2);
1826+
if (v2 instanceof JSONObject) {
1827+
((JSONObject) v2).updateListener = this.updateListener;
1828+
}
1829+
if (!(Objects.equals(v2, v1) && Objects.equals(v1, v2))) {
1830+
this.updateListener.run();
18711831
}
1872-
1873-
1874-
this.propertyChangeSupportUpdate.firePropertyChange(JSONObject.propertyChangeGlobalKeyword, oldThis, this);
1875-
this.propertyChangeSupportUpdate.firePropertyChange(key, oldValue, newValue);
1876-
1877-
this.propertyChangeSupportNotify.firePropertyChange(key, oldValue, newValue);
1878-
18791832
return this;
18801833
}
18811834

1882-
public JSONObject notify(String key, Object oldValue, Object newValue) throws JSONException {
1883-
this.propertyChangeSupportNotify.firePropertyChange(key, oldValue, newValue);
1835+
public JSONObject synchronize(JSONObject jo) throws JSONException {
1836+
jo.forEach((key, v2) -> {
1837+
this.compute(key, (k, v1) -> {
1838+
if (Objects.equals(v1, v2) && Objects.equals(v2, v1)) {
1839+
return v1;
1840+
} else {
1841+
return JSONObject.NULL.equals(v2) ? JSONObject.NULL : v2;
1842+
}
1843+
});
1844+
});
18841845

1885-
return this;
1886-
}
1846+
final String[] names = JSONObject.getNames(this);
1847+
if (names != null) {
1848+
for (String key : names) {
1849+
if (!jo.has(key)) {
1850+
this.remove(key);
1851+
}
1852+
}
1853+
}
18871854

1888-
/**
1889-
* Put a key/value pair in the JSONObject and
1890-
* reports a bound property update to listeners.
1891-
*
1892-
* @param key
1893-
* A key string.
1894-
* @param newValue
1895-
* An object which is the newValue. It should be of one of these
1896-
* types: Boolean, Double, Integer, JSONArray, JSONObject, Long,
1897-
* String, or the JSONObject.NULL object.
1898-
* @return this.
1899-
* @throws JSONException
1900-
* If the newValue is non-finite number.
1901-
* @throws JSONException
1902-
* If updateListener not initialized.
1903-
*/
1904-
public JSONObject update(JSONObject jo) throws JSONException {
1905-
return this.updateOrRemove(jo, false, true);
1855+
return this;
19061856
}
19071857

19081858
/**
@@ -1921,63 +1871,32 @@ public JSONObject update(JSONObject jo) throws JSONException {
19211871
* @throws JSONException
19221872
* If updateListener not initialized.
19231873
*/
1924-
public JSONObject updateOrRemove(JSONObject jo) throws JSONException {
1925-
return this.updateOrRemove(jo, true, true);
1926-
}
1927-
1928-
public JSONObject mix(JSONObject jo) throws JSONException {
1929-
return this.updateOrRemove(jo, false, false);
1930-
}
1931-
1932-
public JSONObject mixOrRemove(JSONObject jo) throws JSONException {
1933-
return this.updateOrRemove(jo, true, false);
1934-
}
1935-
1936-
private JSONObject updateOrRemove(JSONObject jo, boolean remove, boolean triggerUpdate) throws JSONException {
1937-
final JSONObject oldThis = new JSONObject(this.toString());
1938-
1939-
final HashMap<String, Object> oldValues = new HashMap<String, Object>();
1940-
final HashMap<String, Object> newValues = new HashMap<String, Object>();
1941-
final ArrayList<String> delValues = new ArrayList<String>();
1874+
public JSONObject updateSynchronize(JSONObject jo) throws JSONException {
1875+
final AtomicBoolean changed = new AtomicBoolean(false);
19421876

19431877
jo.forEach((key, v2) -> {
19441878
this.compute(key, (k, v1) -> {
19451879
if (Objects.equals(v1, v2) && Objects.equals(v2, v1)) {
19461880
return v1;
19471881
} else {
1948-
oldValues.put(key, JSONObject.NULL.equals(v1) ? null : v1);
1949-
newValues.put(key, JSONObject.NULL.equals(v2) ? null : v2);
1882+
changed.set(true);
19501883
return JSONObject.NULL.equals(v2) ? JSONObject.NULL : v2;
19511884
}
19521885
});
19531886
});
19541887

1955-
if (remove) {
1956-
final String[] names = JSONObject.getNames(this);
1957-
if (names != null) {
1958-
for (String key : names) {
1959-
if (!jo.has(key)) {
1960-
oldValues.put(key, this.remove(key));
1961-
delValues.add(key);
1962-
}
1888+
final String[] names = JSONObject.getNames(this);
1889+
if (names != null) {
1890+
for (String key : names) {
1891+
if (!jo.has(key)) {
1892+
changed.set(true);
1893+
this.remove(key);
19631894
}
19641895
}
19651896
}
19661897

1967-
if (oldValues.size() > 0) {
1968-
if (triggerUpdate) {
1969-
this.propertyChangeSupportUpdate.firePropertyChange(JSONObject.propertyChangeGlobalKeyword, oldThis, this);
1970-
}
1971-
1972-
oldValues.forEach((key, oldValue) -> {
1973-
final Object v2 = delValues.contains(key) ? null : newValues.get(key);
1974-
final Object v1 = oldValue == null && v2 == null ? JSONObject.NULL : oldValue;
1975-
1976-
if (triggerUpdate) {
1977-
this.propertyChangeSupportUpdate.firePropertyChange(key, v1, v2);
1978-
}
1979-
this.propertyChangeSupportNotify.firePropertyChange(key, v1, v2);
1980-
});
1898+
if (changed.get()) {
1899+
this.updateListener.run();
19811900
}
19821901

19831902
return this;

0 commit comments

Comments
 (0)