Repository: OpenRefine/OpenRefine (java)

Issue:
Restore deleted constructor to StandardReconConfig
Per https://github.com/OpenRefine/OpenRefine/issues/6581#issuecomment-2138895162 fix incompatible public API changes that cause compilation errors:
```
no suitable constructor found for StandardReconConfig(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,boolean,java.util.ArrayList<com.google.refine.model.recon.StandardReconConfig.ColumnDetail>,int)
```

\
### Current Results
Existing extensions don't compile.

### Expected Behavior
Both binary and source compatibility are preserved for extensions



Pull request:
Restore public API. Fixes #6652
Draft while I figure out the intricacies of Jackson annotations...

Fixes #6652

Changes proposed in this pull request:
- Restore deleted public constructors & getters 



Patch:
diff --git a/main/pom.xml b/main/pom.xml
index 7c94f8575..c96083ed6 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -208,6 +208,11 @@
       <artifactId>jackson-annotations</artifactId>
       <version>${jackson.version}</version>
     </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.datatype</groupId>
+      <artifactId>jackson-datatype-jdk8</artifactId>
+      <version>${jackson.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
diff --git a/main/src/com/google/refine/importers/WikitextImporter.java b/main/src/com/google/refine/importers/WikitextImporter.java
index 87614eba2..09506f8cb 100644
--- a/main/src/com/google/refine/importers/WikitextImporter.java
+++ b/main/src/com/google/refine/importers/WikitextImporter.java
@@ -774,7 +774,6 @@ public class WikitextImporter extends TabularImportingParserBase {
                 "",
                 "entity",
                 true,
-                10,
                 new ArrayList<ColumnDetail>(),
                 1);
         return cfg;
diff --git a/main/src/com/google/refine/model/recon/DataExtensionReconConfig.java b/main/src/com/google/refine/model/recon/DataExtensionReconConfig.java
index f961d0119..da5143b95 100644
--- a/main/src/com/google/refine/model/recon/DataExtensionReconConfig.java
+++ b/main/src/com/google/refine/model/recon/DataExtensionReconConfig.java
@@ -53,7 +53,13 @@ public class DataExtensionReconConfig extends StandardReconConfig {
             String identifierSpace,
             String schemaSpace,
             ReconType type) {
-        super(service, identifierSpace, schemaSpace, type != null ? type.id : null, type != null ? type.name : null, true, 10,
+        super(
+                service,
+                identifierSpace,
+                schemaSpace,
+                type != null ? type.id : null,
+                type != null ? type.name : null,
+                true,
                 new ArrayList<ColumnDetail>());
         this.type = type;
     }
@@ -64,6 +70,11 @@ public class DataExtensionReconConfig extends StandardReconConfig {
         throw new RuntimeException(WARN);
     }
 
+    @Override
+    public int getBatchSize() {
+        throw new RuntimeException(WARN);
+    }
+
     @Override
     public int getBatchSize(int rowCount) {
         throw new RuntimeException(WARN);
diff --git a/main/src/com/google/refine/model/recon/ReconConfig.java b/main/src/com/google/refine/model/recon/ReconConfig.java
index 62587efee..4f3c049d1 100644
--- a/main/src/com/google/refine/model/recon/ReconConfig.java
+++ b/main/src/com/google/refine/model/recon/ReconConfig.java
@@ -98,6 +98,10 @@ abstract public class ReconConfig {
         return ParsingUtilities.mapper.readValue(json, ReconConfig.class);
     }
 
+    @Deprecated
+    @JsonIgnore
+    public abstract int getBatchSize();
+
     @JsonIgnore
     public abstract int getBatchSize(int rowCount);
 
diff --git a/main/src/com/google/refine/model/recon/StandardReconConfig.java b/main/src/com/google/refine/model/recon/StandardReconConfig.java
index 2392310b0..77556fc2b 100644
--- a/main/src/com/google/refine/model/recon/StandardReconConfig.java
+++ b/main/src/com/google/refine/model/recon/StandardReconConfig.java
@@ -42,6 +42,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
@@ -49,6 +50,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonInclude;
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import com.fasterxml.jackson.annotation.Nulls;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -75,6 +78,7 @@ public class StandardReconConfig extends ReconConfig {
 
     private static final String DEFAULT_SCHEMA_SPACE = "http://localhost/schema";
     private static final String DEFAULT_IDENTIFIER_SPACE = "http://localhost/identifier";
+    private static final int DEFAULT_BATCH_SIZE = 10;
 
     static public class ColumnDetail {
 
@@ -88,6 +92,8 @@ public class StandardReconConfig extends ReconConfig {
         /**
          * Unfortunately the format of ColumnDetail is inconsistent in the UI and the backend so we need to support two
          * deserialization formats. See the tests for that.
+         *
+         * FIXME: Clean this up the next time we make breaking changes
          */
         @JsonCreator
         public ColumnDetail(
@@ -143,8 +149,10 @@ public class StandardReconConfig extends ReconConfig {
     final public String typeName;
     @JsonProperty("autoMatch")
     final public boolean autoMatch;
+    @JsonInclude(Include.NON_EMPTY)
+    @JsonSetter(nulls = Nulls.SKIP)
     @JsonProperty("batchSize")
-    final public int batchSize;
+    final public Optional<Integer> batchSize;
     @JsonProperty("columnDetails")
     final public List<ColumnDetail> columnDetails;
     @JsonProperty("limit")
@@ -160,7 +168,7 @@ public class StandardReconConfig extends ReconConfig {
             @JsonProperty("schemaSpace") String schemaSpace,
             @JsonProperty("type") ReconType type,
             @JsonProperty("autoMatch") boolean autoMatch,
-            @JsonProperty("batchSize") int batchSize,
+            @JsonProperty("batchSize") Optional<Integer> batchSize,
             @JsonProperty("columnDetails") List<ColumnDetail> columnDetails,
             @JsonProperty("limit") int limit) {
         this(service, identifierSpace, schemaSpace,
@@ -173,13 +181,66 @@ public class StandardReconConfig extends ReconConfig {
             String service,
             String identifierSpace,
             String schemaSpace,
+            ReconType type,
+            boolean autoMatch,
+            List<ColumnDetail> columnDetails,
+            int limit) {
+        this(service, identifierSpace, schemaSpace,
+                type != null ? type.id : null,
+                type != null ? type.name : null,
+                autoMatch, columnDetails, limit);
+    }
 
+    /**
+     * Recently added by mistake, so slated for removal quickly after a short deprecation period.
+     * 
+     * @since 3.8.0
+     * @deprecated for 3.8.3
+     */
+    @Deprecated(since = "3.8.3")
+    public StandardReconConfig(
+            String service,
+            String identifierSpace,
+            String schemaSpace,
+            ReconType type,
+            boolean autoMatch,
+            int batchSize,
+            List<ColumnDetail> columnDetails,
+            int limit) {
+        this(service, identifierSpace, schemaSpace,
+                type != null ? type.id : null,
+                type != null ? type.name : null,
+                autoMatch, Optional.of(batchSize), columnDetails, limit);
+    }
+
+    public StandardReconConfig(
+            String service,
+            String identifierSpace,
+            String schemaSpace,
+            String typeID,
+            String typeName,
+            boolean autoMatch,
+            List<ColumnDetail> columnDetails) {
+        this(service, identifierSpace, schemaSpace, typeID, typeName, autoMatch, Optional.empty(), columnDetails, 0);
+    }
+
+    /**
+     * Recently added by mistake, so slated for removal quickly after a short deprecation period.
+     * 
+     * @since 3.8.0
+     * @deprecated for 3.8.3
+     */
+    @Deprecated(since = "3.8.3")
+    public StandardReconConfig(
+            String service,
+            String identifierSpace,
+            String schemaSpace,
             String typeID,
             String typeName,
             boolean autoMatch,
             int batchSize,
             List<ColumnDetail> columnDetails) {
-        this(service, identifierSpace, schemaSpace, typeID, typeName, autoMatch, batchSize, columnDetails, 0);
+        this(service, identifierSpace, schemaSpace, typeID, typeName, autoMatch, Optional.of(batchSize), columnDetails, 0);
     }
 
     /**
@@ -200,7 +261,30 @@ public class StandardReconConfig extends ReconConfig {
             String typeID,
             String typeName,
             boolean autoMatch,
-            int batchSize,
+            List<ColumnDetail> columnDetails,
+            int limit) {
+        this(service, identifierSpace, schemaSpace, typeID, typeName, autoMatch, Optional.empty(), columnDetails, limit);
+    }
+
+    /**
+     * @param service
+     * @param identifierSpace
+     * @param schemaSpace
+     * @param typeID
+     * @param typeName
+     * @param autoMatch
+     * @param columnDetails
+     * @param limit
+     *            maximum number of results to return (0 = default)
+     */
+    public StandardReconConfig(
+            String service,
+            String identifierSpace,
+            String schemaSpace,
+            String typeID,
+            String typeName,
+            boolean autoMatch,
+            Optional<Integer> batchSize,
             List<ColumnDetail> columnDetails,
             int limit) {
         this.service = service;
@@ -224,10 +308,20 @@ public class StandardReconConfig extends ReconConfig {
         return null;
     }
 
+    @Deprecated
+    @Override
+    @JsonIgnore
+    public int getBatchSize() {
+        return DEFAULT_BATCH_SIZE;
+    }
+
     @Override
     @JsonIgnore
     public int getBatchSize(int rowCount) {
-        return Math.min(Math.max(rowCount / 10, 10), batchSize);
+        if (batchSize.isEmpty()) {
+            return DEFAULT_BATCH_SIZE;
+        }
+        return Math.min(Math.max(rowCount / DEFAULT_BATCH_SIZE, DEFAULT_BATCH_SIZE), batchSize.get());
     }
 
     @Override
@@ -348,6 +442,8 @@ public class StandardReconConfig extends ReconConfig {
         public double score;
         @JsonProperty("match")
         public boolean match = false;
+        // TODO: Do we have a way of testing this for compatibility? Hopefully clients ignore unknown fields
+        @JsonInclude(Include.NON_NULL)
         @JsonProperty("error")
         public ReconCandidate error = null;
 
@@ -509,6 +605,7 @@ public class StandardReconConfig extends ReconConfig {
 
         while (recons.size() < jobs.size()) {
             Recon recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
+            // TODO: Needs i18n
             recon.error = "No. of recon objects was less than no. of jobs";
             recon.judgment = Judgment.Error;
             recons.add(recon);
@@ -571,6 +668,7 @@ public class StandardReconConfig extends ReconConfig {
             if (candidate.name != null) {
                 recon.setFeature(Recon.Feature_nameMatch, text.equalsIgnoreCase(candidate.name));
                 recon.setFeature(Recon.Feature_nameLevenshtein,
+                        // TODO: Probably want diacritic folding as well as case folding here for i18n
                         StringUtils.getLevenshteinDistance(StringUtils.lowerCase(text), StringUtils.lowerCase(candidate.name)));
                 recon.setFeature(Recon.Feature_nameWordDistance, wordDistance(text, candidate.name));
             }
@@ -610,7 +708,7 @@ public class StandardReconConfig extends ReconConfig {
 
     static final protected Set<String> s_stopWords = new HashSet<String>();
     static {
-        // FIXME: This is English specific
+        // FIXME: This is English specific - needs i18n
         s_stopWords.add("the");
         s_stopWords.add("a");
         s_stopWords.add("and");
@@ -622,6 +720,7 @@ public class StandardReconConfig extends ReconConfig {
     }
 
     static protected Set<String> breakWords(String s) {
+        // TODO: This needs i18n
         String[] words = s.toLowerCase().split("\\s+");
 
         Set<String> set = new HashSet<String>(words.length);
diff --git a/main/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperation.java b/main/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperation.java
index 0bcf3654c..7240c3779 100644
--- a/main/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperation.java
+++ b/main/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperation.java
@@ -130,7 +130,6 @@ public class ReconMarkNewTopicsOperation extends EngineDependentMassCellOperatio
                         _schemaSpace,
                         null,
                         false,
-                        10,
                         Collections.emptyList(),
                         0);
     }
diff --git a/main/src/com/google/refine/operations/recon/ReconUseValuesAsIdentifiersOperation.java b/main/src/com/google/refine/operations/recon/ReconUseValuesAsIdentifiersOperation.java
index 41dbcbc4a..d3df56919 100644
--- a/main/src/com/google/refine/operations/recon/ReconUseValuesAsIdentifiersOperation.java
+++ b/main/src/com/google/refine/operations/recon/ReconUseValuesAsIdentifiersOperation.java
@@ -74,7 +74,7 @@ public class ReconUseValuesAsIdentifiersOperation extends EngineDependentMassCel
         this.service = service;
         this.identifierSpace = identifierSpace;
         this.schemaSpace = schemaSpace;
-        this.reconConfig = new StandardReconConfig(service, identifierSpace, schemaSpace, null, null, true, 10, Collections.emptyList());
+        this.reconConfig = new StandardReconConfig(service, identifierSpace, schemaSpace, null, null, true, Collections.emptyList());
     }
 
     @Override
diff --git a/main/src/com/google/refine/util/ParsingUtilities.java b/main/src/com/google/refine/util/ParsingUtilities.java
index f7bfbd392..806ce1a4c 100644
--- a/main/src/com/google/refine/util/ParsingUtilities.java
+++ b/main/src/com/google/refine/util/ParsingUtilities.java
@@ -66,6 +66,7 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import com.fasterxml.jackson.databind.ser.FilterProvider;
 import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
 import org.apache.commons.codec.DecoderException;
 import org.apache.commons.codec.net.URLCodec;
 import org.apache.commons.io.IOUtils;
@@ -90,6 +91,7 @@ public class ParsingUtilities {
         module.addDeserializer(Instant.class, new SerializationFilters.InstantDeserializer());
 
         mapper.registerModule(module);
+        mapper.registerModule(new Jdk8Module()/* .configureAbsentsAsNulls(true) */);
         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
         mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
     }
diff --git a/main/webapp/modules/core/about.html b/main/webapp/modules/core/about.html
index 50b1cf423..0af5a5a37 100644
--- a/main/webapp/modules/core/about.html
+++ b/main/webapp/modules/core/about.html
@@ -62,7 +62,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   <body>
     <div id="header">
       <a id="app-home-button" href="./">
-        <img aria-hidden="true" src="images/logo-gem-126.png" width="30" />
+        <img aria-hidden="true" src="images/logo-gem-126.svg" width="30" />
         <h1>OpenRefine</h1>
       </a>
     </div>
diff --git a/main/webapp/modules/core/error.vt b/main/webapp/modules/core/error.vt
index effae65d6..6c997645a 100644
--- a/main/webapp/modules/core/error.vt
+++ b/main/webapp/modules/core/error.vt
@@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   <body>
     <div id="header">
       <a id="app-home-button" href="./" title="Navigate to the home screen">
-        <img aria-hidden="true" src="images/logo-gem-126.png" width="30" />
+        <img aria-hidden="true" src="images/logo-gem-126.svg" width="30" />
         <h1>OpenRefine</h1>
       </a>
     </div>
diff --git a/main/webapp/modules/core/images/logo-gem-126.svg b/main/webapp/modules/core/images/logo-gem-126.svg
new file mode 100644
index 000000000..ae944f61d
--- /dev/null
+++ b/main/webapp/modules/core/images/logo-gem-126.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.1" viewBox="-20 -6.5 160 151" xmlns="http://www.w3.org/2000/svg">
+ <g transform="translate(0 -8.2001)" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round" stroke-width="4px">
+  <polygon points="31.5 31.5 63 31.5 31.5 63" fill="#00dcff"/>
+  <polygon points="31.5 31.5 0 63 31.5 63" fill="#0ff"/>
+  <polygon points="94.5 31.5 63 31.5 94.5 63" fill="#00b4ff"/>
+  <polygon points="63 31.5 94.5 63 31.5 63" fill="#00c8ff"/>
+  <polygon points="94.5 31.5 126 63 94.5 63" fill="#00a0ff"/>
+  <polygon points="0 63 63 126 31.5 63" fill="#00c8ff"/>
+  <polygon points="31.5 63 63 126 94.5 63" fill="#00a0ff"/>
+  <polygon points="94.5 63 63 126 126 63" fill="#0078ff"/>
+ </g>
+</svg>
diff --git a/main/webapp/modules/core/index.vt b/main/webapp/modules/core/index.vt
index 327ee612a..ecac2668a 100644
--- a/main/webapp/modules/core/index.vt
+++ b/main/webapp/modules/core/index.vt
@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 </head>
 <body>
   <div id="header">
-    <img alt="OpenRefine logo" src="images/logo-gem-126.png" width="30" />
+    <img alt="OpenRefine logo" src="images/logo-gem-126.svg" width="30" />
     <h1>OpenRefine</h1>
     <span id="slogan"></span>
   </div>
@@ -55,7 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     
     <div id="project-links">
       <div id="logo-container">
-        <img alt="OpenRefine" src="images/logo-gem-126.png" height="65" />
+        <img alt="OpenRefine" src="images/logo-gem-126.svg" height="65" />
         <div id="openrefine-version"></div>
       </div>
       <ul>
diff --git a/main/webapp/modules/core/preferences.vt b/main/webapp/modules/core/preferences.vt
index e1b7d5372..4bbb16547 100644
--- a/main/webapp/modules/core/preferences.vt
+++ b/main/webapp/modules/core/preferences.vt
@@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 <body>
   <div id="header">
     <a id="app-home-button" href="./">
-      <img aria-hidden="true" src="images/logo-gem-126.png" width="30" />
+      <img aria-hidden="true" src="images/logo-gem-126.svg" width="30" />
       <h1>OpenRefine</h1>
     </a>
   </div>
diff --git a/main/webapp/modules/core/project.vt b/main/webapp/modules/core/project.vt
index 7c21ea12a..8d4fe782e 100644
--- a/main/webapp/modules/core/project.vt
+++ b/main/webapp/modules/core/project.vt
@@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   <body>
     <div id="header">
       <a id="app-home-button" href="./">
-        <img aria-hidden="true" src="images/logo-gem-126.png" width="30" />
+        <img aria-hidden="true" src="images/logo-gem-126.svg" width="30" />
         <h1>OpenRefine</h1>
       </a>
       <div id="project-title">
diff --git a/main/webapp/modules/core/styles/project/sidebar.css b/main/webapp/modules/core/styles/project/sidebar.css
index 65b5afa9b..b3274079f 100644
--- a/main/webapp/modules/core/styles/project/sidebar.css
+++ b/main/webapp/modules/core/styles/project/sidebar.css
@@ -91,7 +91,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   padding: 20px 0 0 10px;
   font-size: 1.15em;
   font-weight: bold;
-  background: url(../../images/logo-gem-126.png) no-repeat top right;
+  background: url(../../images/logo-gem-126.svg) no-repeat top right;
   background-size: 43px;
 }
 


Test patch:
diff --git a/extensions/wikibase/tests/src/org/openrefine/wikibase/editing/NewEntityLibraryTest.java b/extensions/wikibase/tests/src/org/openrefine/wikibase/editing/NewEntityLibraryTest.java
index d3c297c60..b25f029fe 100644
--- a/extensions/wikibase/tests/src/org/openrefine/wikibase/editing/NewEntityLibraryTest.java
+++ b/extensions/wikibase/tests/src/org/openrefine/wikibase/editing/NewEntityLibraryTest.java
@@ -62,7 +62,7 @@ public class NewEntityLibraryTest extends WikidataRefineTest {
         Project project = createProject(TestingData.inceptionColumns,
                 TestingData.inceptionProjectGridWithNewItem);
         StandardReconConfig config = new StandardReconConfig("http://my.endpoint",
-                "http://my.schema", "http://my.schema", "Q5", "human", true, 10, Collections.emptyList());
+                "http://my.schema", "http://my.schema", "Q5", "human", true, Collections.emptyList());
         project.columnModel.columns.get(0).setReconConfig(config);
 
         project.rows.get(0).cells.set(0, TestingData.makeNewItemCell(3289L, "University of Ljubljana"));
diff --git a/main/tests/server/src/com/google/refine/commands/recon/ReconJudgeOneCellCommandTest.java b/main/tests/server/src/com/google/refine/commands/recon/ReconJudgeOneCellCommandTest.java
index 6e334149e..8425a4549 100644
--- a/main/tests/server/src/com/google/refine/commands/recon/ReconJudgeOneCellCommandTest.java
+++ b/main/tests/server/src/com/google/refine/commands/recon/ReconJudgeOneCellCommandTest.java
@@ -76,7 +76,7 @@ public class ReconJudgeOneCellCommandTest extends RefineTest {
                 "http://my.recon.service/rdf/schema",
                 "type3894",
                 "octopus",
-                true, 10,
+                true,
                 Collections.emptyList(),
                 5);
         reconciled.setReconConfig(config);
diff --git a/main/tests/server/src/com/google/refine/model/ColumnTests.java b/main/tests/server/src/com/google/refine/model/ColumnTests.java
index f367dd415..da6c02902 100644
--- a/main/tests/server/src/com/google/refine/model/ColumnTests.java
+++ b/main/tests/server/src/com/google/refine/model/ColumnTests.java
@@ -54,7 +54,6 @@ public class ColumnTests {
                 + "   \"schemaSpace\":\"http://www.wikidata.org/prop/direct/\","
                 + "   \"type\":{\"id\":\"Q43229\",\"name\":\"organization\"},"
                 + "   \"autoMatch\":true,"
-                + "   \"batchSize\":10,"
                 + "   \"columnDetails\":["
                 + "      {\"column\":\"organization_country\",\"propertyName\":\"SPARQL: P17/P297\",\"propertyID\":\"P17/P297\"},"
                 + "      {\"column\":\"organization_id\",\"propertyName\":\"SPARQL: P3500|P2427\",\"propertyID\":\"P3500|P2427\"}"
diff --git a/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java b/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
index 005b92f34..0a69a985e 100644
--- a/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
+++ b/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
@@ -77,7 +77,7 @@ public class StandardReconConfigTests extends RefineTest {
     private class StandardReconConfigStub extends StandardReconConfig {
 
         public StandardReconConfigStub() {
-            super("", "", "", "", "", false, 10, new ArrayList<ColumnDetail>());
+            super("", "", "", "", "", false, new ArrayList<ColumnDetail>());
         }
 
         public double wordDistanceTest(String s1, String s2) {
@@ -118,7 +118,41 @@ public class StandardReconConfigTests extends RefineTest {
                 "                \"name\": \"scientific article\"\n" +
                 "        },\n" +
                 "        \"autoMatch\": true,\n" +
-                "        \"batchSize\": 10,\n" +
+                "        \"columnDetails\": [\n" +
+                "           {\n" +
+                "             \"column\": \"organization_country\",\n" +
+                "             \"propertyName\": \"SPARQL: P17/P297\",\n" +
+                "             \"propertyID\": \"P17/P297\"\n" +
+                "           },\n" +
+                "           {\n" +
+                "             \"column\": \"organization_id\",\n" +
+                "             \"propertyName\": \"SPARQL: P3500|P2427\",\n" +
+                "             \"propertyID\": \"P3500|P2427\"\n" +
+                "           }\n" +
+                "        ],\n" +
+                "        \"limit\": 0\n" +
+                " }";
+        ReconConfig config = ReconConfig.reconstruct(json);
+        TestUtils.isSerializedTo(config, json);
+
+        // the "mode" only appears once in the serialization result
+        String fullJson = ParsingUtilities.mapper.writeValueAsString(config);
+        assertEquals(fullJson.indexOf("\"mode\"", fullJson.indexOf("\"mode\"") + 1), -1);
+    }
+
+    @Test
+    public void serializeStandardReconConfigWithBatchSize() throws Exception {
+        String json = " {\n" +
+                "        \"mode\": \"standard-service\",\n" +
+                "        \"service\": \"https://tools.wmflabs.org/openrefine-wikidata/en/api\",\n" +
+                "        \"identifierSpace\": \"http://www.wikidata.org/entity/\",\n" +
+                "        \"schemaSpace\": \"http://www.wikidata.org/prop/direct/\",\n" +
+                "        \"type\": {\n" +
+                "                \"id\": \"Q13442814\",\n" +
+                "                \"name\": \"scientific article\"\n" +
+                "        },\n" +
+                "        \"autoMatch\": true,\n" +
+                "        \"batchSize\": 20,\n" +
                 "        \"columnDetails\": [\n" +
                 "           {\n" +
                 "             \"column\": \"organization_country\",\n" +
diff --git a/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperationTests.java b/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperationTests.java
index cf18dc1f5..de60cb80d 100644
--- a/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperationTests.java
+++ b/main/tests/server/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperationTests.java
@@ -78,7 +78,6 @@ public class ReconJudgeSimilarCellsOperationTests extends RefineTest {
                 schemaSpace,
                 null,
                 true,
-                10,
                 Collections.emptyList(),
                 5);
         project = createProject(
@@ -134,7 +133,8 @@ public class ReconJudgeSimilarCellsOperationTests extends RefineTest {
                 "http://my.database/schema/",
                 null,
                 null,
-                true, 10, Collections.emptyList());
+                true,
+                Collections.emptyList());
         column.setReconConfig(config);
 
         AbstractOperation op = new ReconJudgeSimilarCellsOperation(
diff --git a/main/tests/server/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperationTests.java b/main/tests/server/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperationTests.java
index dd71428d6..1e4759d17 100644
--- a/main/tests/server/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperationTests.java
+++ b/main/tests/server/src/com/google/refine/operations/recon/ReconMarkNewTopicsOperationTests.java
@@ -113,7 +113,7 @@ public class ReconMarkNewTopicsOperationTests extends RefineTest {
                 "http://foo.com/identifierSpace",
                 "http://foo.com/schemaSpace",
                 null,
-                false, 10,
+                false,
                 Collections.emptyList(),
                 0);
 
diff --git a/main/tests/server/src/com/google/refine/operations/recon/ReconOperationTests.java b/main/tests/server/src/com/google/refine/operations/recon/ReconOperationTests.java
index 87fb12401..b03b83e35 100644
--- a/main/tests/server/src/com/google/refine/operations/recon/ReconOperationTests.java
+++ b/main/tests/server/src/com/google/refine/operations/recon/ReconOperationTests.java
@@ -87,7 +87,6 @@ public class ReconOperationTests extends RefineTest {
             + "   \"schemaSpace\":\"http://www.wikidata.org/prop/direct/\","
             + "   \"type\":{\"id\":\"Q5\",\"name\":\"human\"},"
             + "   \"autoMatch\":true,"
-            + "   \"batchSize\":10,"
             + "   \"columnDetails\":[],"
             + "   \"limit\":0"
             + "},"
@@ -174,6 +173,7 @@ public class ReconOperationTests extends RefineTest {
         recon3.judgment = Judgment.Matched;
 
         reconConfig = mock(StandardReconConfig.class, withSettings().serializable());
+        doReturn(2).when(reconConfig).getBatchSize();
         doReturn(2).when(reconConfig).getBatchSize(anyInt());
         // mock identifierSpace, service and schemaSpace
         when(reconConfig.batchRecon(eq(Arrays.asList(job1, job2)), anyLong())).thenReturn(Arrays.asList(recon1, recon2));
@@ -236,6 +236,7 @@ public class ReconOperationTests extends RefineTest {
         List<Recon> reconList = Arrays.asList((Recon) null, (Recon) null, (Recon) null);
         ReconJob reconJob = mock(ReconJob.class);
         when(reconConfig.batchRecon(Mockito.any(), Mockito.anyLong())).thenReturn(reconList);
+        when(reconConfig.getBatchSize()).thenReturn(10);
         when(reconConfig.getBatchSize(project.rows.size())).thenReturn(10);
         when(reconConfig.createJob(Mockito.eq(project), Mockito.anyInt(), Mockito.any(), Mockito.any(), Mockito.any()))
                 .thenReturn(reconJob);