Jackson deserialization for PreferenceStore

This commit is contained in:
Antonin Delpeuch 2018-11-03 14:49:01 +00:00
parent 5cf58d874b
commit fc7da40055
7 changed files with 77 additions and 80 deletions

View File

@ -42,9 +42,11 @@ import javax.servlet.http.HttpServletResponse;
import org.json.JSONException;
import org.json.JSONTokener;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.refine.ProjectManager;
import com.google.refine.model.Project;
import com.google.refine.preference.PreferenceStore;
import com.google.refine.util.ParsingUtilities;
public class SetPreferenceCommand extends Command {
@Override
@ -58,12 +60,12 @@ public class SetPreferenceCommand extends Command {
String valueString = request.getParameter("value");
try {
Object o = valueString == null ? null : new JSONTokener(valueString).nextValue();
JsonNode o = valueString == null ? null : ParsingUtilities.mapper.readTree(valueString);
ps.put(prefName, PreferenceStore.loadObject(o));
respond(response, "{ \"code\" : \"ok\" }");
} catch (JSONException e) {
} catch (IOException e) {
respondException(response, e);
}
}

View File

@ -67,6 +67,7 @@ import com.google.refine.model.metadata.DataPackageMetadata;
import com.google.refine.model.metadata.IMetadata;
import com.google.refine.model.metadata.MetadataFormat;
import com.google.refine.model.metadata.ProjectMetadata;
import com.google.refine.preference.PreferenceStore;
import com.google.refine.preference.TopList;
import com.google.refine.util.ParsingUtilities;
@ -386,7 +387,7 @@ public class FileProjectManager extends ProjectManager {
// load global preferences firstly
if (obj.has("preferences") && !obj.isNull("preferences")) {
_preferenceStore.load(obj.getJSONObject("preferences"));
_preferenceStore = ParsingUtilities.mapper.readValue(obj.getJSONObject("preferences").toString(), PreferenceStore.class);
}
JSONArray a = obj.getJSONArray("projectIDs");
@ -413,8 +414,8 @@ public class FileProjectManager extends ProjectManager {
}
if (obj.has("expressions") && !obj.isNull("expressions")) { // backward compatibility
((TopList) _preferenceStore.get("scripting.expressions"))
.load(obj.getJSONArray("expressions"));
TopList newExpressions = ParsingUtilities.mapper.readValue(obj.getJSONArray("expressions").toString(), TopList.class);
this._preferenceStore.put("scripting.expressions", newExpressions);
}
found = true;

View File

@ -205,16 +205,17 @@ public class ProjectMetadata extends AbstractMetadata {
if (obj.has("preferences") && !obj.isNull("preferences")) {
try {
this._preferenceStore.load(obj.getJSONObject("preferences"));
} catch (JSONException e) {
this._preferenceStore = ParsingUtilities.mapper.readValue(obj.getJSONObject("preferences").toString(), PreferenceStore.class);
} catch (IOException e) {
logger.error(ExceptionUtils.getStackTrace(e));
}
}
if (obj.has("expressions") && !obj.isNull("expressions")) { // backward compatibility
try {
((TopList) this._preferenceStore.get("scripting.expressions")).load(obj.getJSONArray("expressions"));
} catch (JSONException e) {
TopList newExpressions = ParsingUtilities.mapper.readValue(obj.getJSONArray("expressions").toString(), TopList.class);
this._preferenceStore.put("scripting.expressions", newExpressions);
} catch (IOException e) {
logger.error(ExceptionUtils.getStackTrace(e));
}
}

View File

@ -34,7 +34,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.refine.preference;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@ -50,8 +49,9 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.refine.RefineServlet;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.refine.util.ParsingUtilities;
public class PreferenceStore {
public static final String USER_METADATA_KEY = "userMetadata";
@ -63,7 +63,6 @@ public class PreferenceStore {
protected Map<String, Object> _prefs = new HashMap<>();
// Temporary wrapper while serialization has not been migrated yet.
@JsonProperty("entries")
protected Map<String, Object> _prefsJackson = new HashMap<>();
public void put(String key, Object value) {
@ -119,39 +118,43 @@ public class PreferenceStore {
return null;
}
@SuppressWarnings("unchecked")
public void load(JSONObject obj) throws JSONException {
if (obj.has("entries") && !obj.isNull("entries")) {
JSONObject entries = obj.getJSONObject("entries");
Iterator<String> i = entries.keys();
while (i.hasNext()) {
String key = i.next();
if (!entries.isNull(key)) {
Object o = entries.get(key), loaded = loadObject(o);
_prefs.put(key, loaded);
_prefsJackson.put(key, wrapJSONArray(loaded));
}
@JsonProperty("entries")
public void setEntries(JsonNode entries) throws JSONException {
Iterator<String> i = entries.fieldNames();
while (i.hasNext()) {
String key = i.next();
System.out.println(key);
if (entries.get(key) != null) {
JsonNode o = entries.get(key);
Object loaded = loadObject(o);
_prefs.put(key, loaded);
_prefsJackson.put(key, wrapJSONArray(loaded));
}
dirty = false; // internal puts don't count
}
dirty = false; // internal puts don't count
}
static public Object loadObject(Object o) {
if (o instanceof JSONObject) {
try {
JSONObject obj2 = (JSONObject) o;
String className = obj2.getString("class");
Class<?> klass = RefineServlet.getClass(className);
Method method = klass.getMethod("load", JSONObject.class);
return method.invoke(null, obj2);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} else {
return o;
@JsonProperty("entries")
public Map<String, Object> getEntries() {
return _prefsJackson;
}
static public Object loadObject(JsonNode o) {
System.out.println("loading");
System.out.println(o.toString());
try {
if (o instanceof ObjectNode) {
ObjectNode obj2 = (ObjectNode) o;
return ParsingUtilities.mapper.treeToValue(obj2, PreferenceValue.class);
} else if (o instanceof ArrayNode) {
return o;
} else {
// basic datatypes (int, double, boolean, string)
return ParsingUtilities.mapper.treeToValue(o, Object.class);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -38,24 +38,32 @@ import java.util.Iterator;
import java.util.List;
import org.apache.commons.collections.list.UnmodifiableList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
public class TopList implements Iterable<String> {
public class TopList implements Iterable<String>, PreferenceValue {
@JsonProperty("top")
final protected int _top;
final protected List<String> _list = new ArrayList<String>();
protected int _top = 10;
protected List<String> _list = new ArrayList<String>();
public TopList(int top) {
_top = top;
}
@JsonCreator
public TopList(
@JsonProperty("top")
int top,
@JsonProperty("list")
List<String> list) {
_top = top;
_list = list;
}
@SuppressWarnings("unchecked")
@JsonProperty("list")
public List<String> getList() {
@ -75,30 +83,6 @@ public class TopList implements Iterable<String> {
_list.remove(element);
}
@JsonProperty("class")
public String getClassName() {
return this.getClass().getName();
}
static public TopList load(JSONObject obj) throws JSONException {
int top = obj.has("top") && !obj.isNull("top") ? obj.getInt("top") : 10;
TopList tl = new TopList(top);
if (obj.has("list") && !obj.isNull("list")) {
JSONArray a = obj.getJSONArray("list");
tl.load(a);
}
return tl;
}
public void load(JSONArray a) throws JSONException {
int length = a.length();
for (int i = 0; i < length && _list.size() < _top; i++) {
_list.add(a.getString(i));
}
}
@Override
@JsonIgnore
public Iterator<String> iterator() {

View File

@ -3,12 +3,15 @@ package com.google.refine.tests.preference;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.json.JSONObject;
import java.io.IOException;
import org.testng.annotations.Test;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.refine.preference.PreferenceStore;
import com.google.refine.tests.RefineTest;
import com.google.refine.tests.util.TestUtils;
import com.google.refine.util.ParsingUtilities;
public class PreferenceStoreTests {
public static String json = "{"
@ -21,7 +24,7 @@ public class PreferenceStoreTests {
+ "}}";
@Test
public void serializePreferenceStore() {
public void serializePreferenceStore() throws JsonParseException, JsonMappingException, IOException {
String jsonAfter = "{"
+ "\"entries\":{"
@ -32,8 +35,7 @@ public class PreferenceStoreTests {
+ " \"scripting.expressions\":{\"class\":\"com.google.refine.preference.TopList\",\"top\":100,\"list\":[]},"
+ " \"mypreference\":\"myvalue\""
+ "}}";
PreferenceStore prefStore = new PreferenceStore();
prefStore.load(new JSONObject(json));
PreferenceStore prefStore = ParsingUtilities.mapper.readValue(json, PreferenceStore.class);
assertFalse(prefStore.isDirty());
prefStore.put("mypreference", "myvalue");
assertTrue(prefStore.isDirty());

View File

@ -1,14 +1,18 @@
package com.google.refine.tests.preference;
import org.json.JSONObject;
import java.io.IOException;
import org.testng.annotations.Test;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.google.refine.preference.TopList;
import com.google.refine.tests.util.TestUtils;
import com.google.refine.util.ParsingUtilities;
public class TopListTests {
@Test
public void serializeTopList() {
public void serializeTopList() throws JsonParseException, JsonMappingException, IOException {
String json = "{"
+ "\"class\":\"com.google.refine.preference.TopList\","
+ "\"top\":100,"
@ -21,7 +25,7 @@ public class TopListTests {
+ " \"grel:\\\"https://pub.orcid.org/\\\"+value+\\\"/employments\\\"\""
+ "]}";
TestUtils.isSerializedTo(
TopList.load(new JSONObject(json)),
ParsingUtilities.mapper.readValue(json, TopList.class),
json);
}
}