From 025501d04f5c1c044d2a204531d261ec6a6268ae Mon Sep 17 00:00:00 2001 From: Jannik Vierling Date: Mon, 16 Sep 2024 10:09:26 +0200 Subject: [PATCH] Replace git submodule by maven dependency (#67) * Add unit tests for serializer * Update to org.json:json 20230227 The maven build now uses maven to manage the dependency. * Update maven build instructions --- .gitmodules | 6 +- INSTALL.md | 12 +- build.xml | 2 +- lib/JSON-java | 1 + pom.xml | 5 + src/main/java/mmj/pa/PaConstants.java | 5 +- src/main/java/mmj/pa/Serializer.java | 41 +++--- src/main/java/mmj/pa/SessionStore.java | 7 +- src/main/java/mmj/tmff/TMFFAlignColumn.java | 6 +- src/main/java/mmj/tmff/TMFFPreferences.java | 17 +-- .../java/mmj/tmff/TMFFTwoColumnAlignment.java | 6 +- src/main/java/mmj/util/StreamUtil.java | 10 ++ src/main/java/mmj/verify/LRParser.java | 4 +- src/main/java/org/json | 1 - src/test/java/mmj/pa/SerializerTest.java | 124 ++++++++++++++++++ 15 files changed, 193 insertions(+), 54 deletions(-) create mode 160000 lib/JSON-java create mode 100644 src/main/java/mmj/util/StreamUtil.java delete mode 160000 src/main/java/org/json create mode 100644 src/test/java/mmj/pa/SerializerTest.java diff --git a/.gitmodules b/.gitmodules index 759d2e5b..5f0fd749 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "JSON-java"] - path = src/main/java/org/json - url = https://github.com/digama0/JSON-java.git +[submodule "lib/JSON-java"] + path = lib/JSON-java + url = https://github.com/stleary/JSON-java.git diff --git a/INSTALL.md b/INSTALL.md index 6c92707b..256d534e 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -322,16 +322,8 @@ follow the Linux/Unix/Cygwin instructions above. ### Building mmj2 with maven -The mmj2 executable JAR file can be built from the sources with maven. -First run the following commands in the `mmj2/` directory to setup the -git submodules used by mmj2: - -``` -git submodule init -git submodule update -``` - -After that, build the executable JAR file using the following command: +The mmj2 executable JAR file can be built from the sources with maven +using the following command. ``` mvn package diff --git a/build.xml b/build.xml index 01b95ff7..623e8e57 100644 --- a/build.xml +++ b/build.xml @@ -27,7 +27,7 @@ - + diff --git a/lib/JSON-java b/lib/JSON-java new file mode 160000 index 00000000..47fb49b6 --- /dev/null +++ b/lib/JSON-java @@ -0,0 +1 @@ +Subproject commit 47fb49b6a871cd1652870e33e89cbff082bb0ee1 diff --git a/pom.xml b/pom.xml index 40b907b3..9f1d7d78 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,11 @@ nashorn-core 15.4 + + org.json + json + 20230227 + diff --git a/src/main/java/mmj/pa/PaConstants.java b/src/main/java/mmj/pa/PaConstants.java index a0cd5d3c..a9ab8e04 100644 --- a/src/main/java/mmj/pa/PaConstants.java +++ b/src/main/java/mmj/pa/PaConstants.java @@ -113,6 +113,7 @@ import static mmj.pa.ErrorCode.of; import java.awt.Color; +import java.util.List; import java.util.Map; import javax.swing.text.SimpleAttributeSet; @@ -2941,7 +2942,7 @@ public static T addStepContext( .put(SessionStore.KEY_STORE, new JSONObject()) .put(SessionStore.KEY_OVERRIDE, new JSONObject()) .put(SessionStore.KEY_REMOVE, new JSONArray()) - .put("-comments", new JSONArray( + .put("-comments", new JSONArray( List.of( " ======================= The store.json File ========================== ", " ", " mmj2 uses a JSON file for saving and loading settings, called ", @@ -2983,7 +2984,7 @@ public static T addStepContext( " this behavior (so that it instead reverts to some chosen value after ", " every restart) you can either add a RunParm and a LoadSettings before ", " that, or you can put the desired key-value pair in the 'manual' ", - " section. ")); + " section. "))); // ---------------------------------------------------------- // Messages from EraseWffsPreprocessRequest.java diff --git a/src/main/java/mmj/pa/Serializer.java b/src/main/java/mmj/pa/Serializer.java index 53e82ace..a24fe49f 100644 --- a/src/main/java/mmj/pa/Serializer.java +++ b/src/main/java/mmj/pa/Serializer.java @@ -20,6 +20,7 @@ import java.util.function.*; import java.util.stream.Collectors; +import mmj.util.StreamUtil; import org.json.*; import mmj.lang.*; @@ -72,10 +73,10 @@ public Object serialize(final T value) { */ default Serializer array(final IntFunction generator) { return Serializer.of( - o -> ((JSONArray)o).stream().map(this::deserialize) + o -> StreamUtil.stream((JSONArray)o).map(this::deserialize) .toArray(generator), - v -> Arrays.stream(v).map(this::serialize) - .collect(Collectors.toCollection(JSONArray::new))); + v -> new JSONArray(Arrays.stream(v).map(this::serialize) + .collect(Collectors.toList()))); } /** @@ -86,10 +87,10 @@ default Serializer array(final IntFunction generator) { */ default Serializer> list() { return Serializer.of( - o -> ((JSONArray)o).stream().map(this::deserialize) + o -> StreamUtil.stream((JSONArray)o).map(this::deserialize) .collect(Collectors.toList()), - v -> v.stream().map(this::serialize) - .collect(Collectors.toCollection(JSONArray::new))); + v -> new JSONArray(v.stream().map(this::serialize) + .collect(Collectors.toList()))); } /** @@ -100,10 +101,10 @@ default Serializer> list() { */ default Serializer> set() { return Serializer.of( - o -> ((JSONArray)o).stream().map(this::deserialize) + o -> StreamUtil.stream((JSONArray)o).map(this::deserialize) .collect(Collectors.toSet()), - v -> v.stream().map(this::serialize) - .collect(Collectors.toCollection(JSONArray::new))); + v -> new JSONArray(v.stream().map(this::serialize) + .collect(Collectors.toList()))); } /** @@ -114,13 +115,13 @@ default Serializer> set() { */ default Serializer> map() { return Serializer.of( - o -> ((JSONObject)o).entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - e -> deserialize(e.getValue()))), - (final Map v) -> v.entrySet().stream() - .collect(Collectors.toMap(Map.Entry::getKey, - e -> serialize(e.getValue()), (a, b) -> a, - JSONObject::new))); + o -> ((JSONObject)o).keySet().stream() + .collect(Collectors.toMap( + k -> k, + k -> deserialize(((JSONObject) o).get(k)))), + (final Map v) -> new JSONObject(v.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, + e -> serialize(e.getValue()), (a, b) -> a)))); } /** @@ -161,8 +162,10 @@ public static Serializer getFileSerializer( throw new IllegalArgumentException(e); } }, value -> { - final JSONArray a = new JSONArray(value.getRed(), value.getGreen(), - value.getBlue()); + final JSONArray a = new JSONArray(List.of( + value.getRed(), + value.getGreen(), + value.getBlue())); return value.getAlpha() == 255 ? a : a.put(value.getAlpha()); }); @@ -175,7 +178,7 @@ public static Serializer getFileSerializer( } catch (final JSONException e) { throw new IllegalArgumentException(e); } - }, r -> new JSONArray(r.x, r.y, r.width, r.height)); + }, r -> new JSONArray(List.of(r.x, r.y, r.width, r.height))); @SuppressWarnings("unchecked") public static Serializer getArraySerializer(final Class clazz) { diff --git a/src/main/java/mmj/pa/SessionStore.java b/src/main/java/mmj/pa/SessionStore.java index ccca99ce..80a086c5 100644 --- a/src/main/java/mmj/pa/SessionStore.java +++ b/src/main/java/mmj/pa/SessionStore.java @@ -112,8 +112,11 @@ public JSONObject load(final boolean intoSettings, JSONArray remove = o.optJSONArray(KEY_REMOVE); if (remove == null) o.put(KEY_REMOVE, remove = new JSONArray()); - for (final Object key : remove) - store.remove(key); + for (final Object key : remove) { + if (key instanceof String) { + store.remove((String) key); + } + } remove.clear(); merge(intoSettings, store, errors, settingsToLoad); merge(true, o.optJSONObject(KEY_OVERRIDE), errors, settingsToLoad); diff --git a/src/main/java/mmj/tmff/TMFFAlignColumn.java b/src/main/java/mmj/tmff/TMFFAlignColumn.java index 958c0610..73cc75b5 100644 --- a/src/main/java/mmj/tmff/TMFFAlignColumn.java +++ b/src/main/java/mmj/tmff/TMFFAlignColumn.java @@ -27,6 +27,8 @@ import mmj.pa.ErrorCode; import mmj.tmff.TMFFConstants.AlignType; +import java.util.List; + /** * TMFFAlignColumn aligns portions of a sub-expression into a single column when * splitting the sub-expression across multiple lines. @@ -219,9 +221,9 @@ public TMFFAlignColumn(final String maxDepthString, @Override public JSONArray asArray() { - return new JSONArray(TMFFConstants.TMFF_METHOD_USER_NAME_ALIGN_COLUMN, + return new JSONArray(List.of(TMFFConstants.TMFF_METHOD_USER_NAME_ALIGN_COLUMN, maxDepth, alignByValue.toString(), alignAtNbr, - alignAtValue.toString()); + alignAtValue.toString())); } /** diff --git a/src/main/java/mmj/tmff/TMFFPreferences.java b/src/main/java/mmj/tmff/TMFFPreferences.java index 48991b91..f9179149 100644 --- a/src/main/java/mmj/tmff/TMFFPreferences.java +++ b/src/main/java/mmj/tmff/TMFFPreferences.java @@ -209,27 +209,24 @@ public TMFFPreferences(final SessionStore store) { // The ~ is so that it sorts at the end with other big keys store.addSerializable("~" + PFX + "formatArray", - (final JSONObject o) -> o.entrySet().parallelStream() + (final JSONObject o) -> o.toMap().entrySet().parallelStream() .map(e -> new String[]{e.getKey().toString(), (String)e.getValue()}) .forEach(read), - () -> Arrays.stream(tmffFormatArray).filter(f -> f != null) + () -> new JSONObject(Arrays.stream(tmffFormatArray).filter(f -> f != null) .collect(Collectors.toMap(f -> f.getFormatNbr() + "", - f -> f.getFormatScheme().getSchemeName(), (a, b) -> a, - JSONObject::new))); + f -> f.getFormatScheme().getSchemeName(), (a, b) -> a)))); store.addSerializable("~" + PFX + "schemeMap", (final JSONObject o) -> { - for (final Entry e : o.entrySet()) { - final List a = new ArrayList<>( - (JSONArray)e.getValue()); + for (final Entry e : o.toMap().entrySet()) { + final List a = new ArrayList<>(((JSONArray)e.getValue()).toList()); a.add(0, e.getKey()); putToSchemeMap(new TMFFScheme( a.stream().map(Object::toString).toArray(String[]::new))); } - } , () -> tmffSchemeMap.values().parallelStream() + } , () -> new JSONObject(tmffSchemeMap.values().parallelStream() .collect(Collectors.toMap(s -> s.getSchemeName(), - s -> s.getTMFFMethod().asArray(), (a, b) -> a, - JSONObject::new))); + s -> s.getTMFFMethod().asArray(), (a, b) -> a)))); } diff --git a/src/main/java/mmj/tmff/TMFFTwoColumnAlignment.java b/src/main/java/mmj/tmff/TMFFTwoColumnAlignment.java index e1bf6d17..e8650bc9 100644 --- a/src/main/java/mmj/tmff/TMFFTwoColumnAlignment.java +++ b/src/main/java/mmj/tmff/TMFFTwoColumnAlignment.java @@ -26,6 +26,8 @@ import mmj.lang.*; +import java.util.List; + /** * TMFFTwoColumnAlignment aligns portions of a sub-expression into a two columns * when splitting the sub-expression across multiple lines: the left column is @@ -104,8 +106,8 @@ public TMFFTwoColumnAlignment(final String maxDepthString) { @Override public JSONArray asArray() { - return new JSONArray( - TMFFConstants.TMFF_METHOD_USER_NAME_TWO_COLUMN_ALIGNMENT, maxDepth); + return new JSONArray(List.of( + TMFFConstants.TMFF_METHOD_USER_NAME_TWO_COLUMN_ALIGNMENT, maxDepth)); } /** diff --git a/src/main/java/mmj/util/StreamUtil.java b/src/main/java/mmj/util/StreamUtil.java new file mode 100644 index 00000000..079e75fd --- /dev/null +++ b/src/main/java/mmj/util/StreamUtil.java @@ -0,0 +1,10 @@ +package mmj.util; + +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +public class StreamUtil { + public static Stream stream(Iterable iterable) { + return StreamSupport.stream(iterable.spliterator(), false); + } +} diff --git a/src/main/java/mmj/verify/LRParser.java b/src/main/java/mmj/verify/LRParser.java index 5d71382b..ed6260f9 100644 --- a/src/main/java/mmj/verify/LRParser.java +++ b/src/main/java/mmj/verify/LRParser.java @@ -226,7 +226,7 @@ private void initialize() { // state where the only valid move is to shift '}'. boolean bad = false; for (final String head : badTokens) - bad |= rows.get(fwd).transitions.containsKey(head); + bad |= rows.get(fwd).transitions.toMap().containsKey(head); if (bad) { // (Let's pretend that the above optimization did not take // place so we can continue the example.) @@ -406,7 +406,7 @@ private void developState(final Integer index) { else reduce = e.rule; } - else if (!row.transitions.containsKey(head.getId())) { + else if (!row.transitions.toMap().containsKey(head.getId())) { final ParseSet goal = new ParseSet(); set.forEach(state -> { if (head.equals(state.head())) diff --git a/src/main/java/org/json b/src/main/java/org/json deleted file mode 160000 index edfb0c57..00000000 --- a/src/main/java/org/json +++ /dev/null @@ -1 +0,0 @@ -Subproject commit edfb0c57d5619bc7444364451a6d6201457136e7 diff --git a/src/test/java/mmj/pa/SerializerTest.java b/src/test/java/mmj/pa/SerializerTest.java new file mode 100644 index 00000000..80ae12e6 --- /dev/null +++ b/src/test/java/mmj/pa/SerializerTest.java @@ -0,0 +1,124 @@ +package mmj.pa; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.IntFunction; +import java.util.stream.IntStream; + +import static java.util.stream.Collectors.toList; +import static org.junit.Assert.*; + +public class SerializerTest { + + @Test + public void testSerializeObject() { + var serializer = new TestSerializer(); + assertSimilar(new JSONObject("{\"myValue\":3}"), + serializer.serialize(new MyObject(3))); + } + + @Test + public void testDeserializeJsonObject() { + var serializer = new TestSerializer(); + assertEquals(new MyObject(3), + serializer.deserialize(new JSONObject("{\"myValue\":3}"))); + } + + @Test + public void testSerializeArray() { + var serializer = new TestSerializer().array(MyObject[]::new); + assertSimilar(new JSONArray("[]"), serializer.serialize(new MyObject[] { })); + } + + @Test + public void testDeserializeNonEmptyJsonArray() { + var serializer = new TestSerializer().array(MyObject[]::new); + assertArrayEquals( new MyObject[]{ new MyObject(1)}, serializer.deserialize(new JSONArray("[{\"myValue\":1}]"))); + } + + @Test + public void testSerializeNonEmptyArray() { + var serializer = new TestSerializer().array(MyObject[]::new); + assertSimilar(new JSONArray("[{\"myValue\":1}]"), serializer.serialize(new MyObject[] {new MyObject(1)})); + } + + @Test + public void serializingNullThrowsException() { + var serializer = new TestSerializer().array(MyObject[]::new); + assertThrows(NullPointerException.class , () -> serializer.serialize(new MyObject[1])); + } + + @Test + public void testListSerializer() { + var serializer = new TestSerializer().list(); + assertSimilar( new JSONArray("[]"), serializer.serialize(List.of())); + assertThrows(NullPointerException.class, () -> serializer.serialize(List.of(null))); + assertSimilar(new JSONArray("[{\"myValue\":1}]"), serializer.serialize(List.of(new MyObject(1)))); + assertEquals(List.of(new MyObject(1)) , serializer.deserialize(new JSONArray("[{\"myValue\":1}]"))); + } + + @Test + public void testSetSerializer() { + var serializer = new TestSerializer().set(); + assertSimilar(new JSONArray("[]"), serializer.serialize(Set.of())); + assertThrows(NullPointerException.class, () -> serializer.serialize(Set.of(null))); + assertSimilar(new JSONArray("[{\"myValue\":1}]"), serializer.serialize(Set.of(new MyObject(1)))); + assertEquals(Set.of(new MyObject(1)) , serializer.deserialize(new JSONArray("[{\"myValue\":1}]"))); + } + + @Test + public void testMapSerializer() { + var serializer = new TestSerializer().map(); + assertSimilar(new JSONObject("{}"), serializer.serialize(Map.of())); + assertThrows(NullPointerException.class, () -> serializer.serialize(Map.of("abc", null))); + assertSimilar(new JSONObject("{\"key\" : {\"myValue\":1}}"), serializer.serialize(Map.of("key", new MyObject(1)))); + assertEquals(Map.of("key", new MyObject(1)) , serializer.deserialize(new JSONObject("{\"key\" : {\"myValue\":1}}"))); + } + + + class TestSerializer implements Serializer { + + @Override + public MyObject deserialize(Object o) { + if (!(o instanceof JSONObject)) { + return null; + } + return new MyObject((Integer) ((JSONObject)o).get("myValue")); + } + + @Override + public Object serialize(MyObject value) { + return new JSONObject("{" + "myValue:" + value.myValue + "}"); + } + } + + class MyObject { + + MyObject(int myValue) { + this.myValue = myValue; + } + int myValue; + + @Override + public boolean equals(Object other) { + return other instanceof MyObject + && ((MyObject) other).myValue == myValue; + } + } + + private static void assertSimilar(JSONObject expected, Object actual) { + assertTrue("Expected " + expected + " but actual is " + actual, + expected.similar(actual)); + } + + private static void assertSimilar(JSONArray expected, Object actual) { + assertTrue("Expected " + expected + " but actual is " + actual, + expected.similar(actual)); + } +} \ No newline at end of file