This is an automated email from the ASF dual-hosted git repository.

dsmiley pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 06768041f92 SOLR-17635: solr.solrj.javabin.readMapAsNamedList=true 
opt-in (#3163)
06768041f92 is described below

commit 06768041f9223d64e1f07ad821bc2aec269b285b
Author: Renato Haeberli <[email protected]>
AuthorDate: Wed Jun 25 05:47:22 2025 +0200

    SOLR-17635: solr.solrj.javabin.readMapAsNamedList=true opt-in (#3163)
    
    javabin format: provide option to decode maps as SimpleOrderedMap (a 
NamedList & Map)
      instead of LinkedHashMap.  Intended to aid in 10.x compatibility.  Enable 
via sys prop: solr.solrj.javabin.readMapAsNamedList=true
---
 solr/CHANGES.txt                                   |  4 +++
 .../solrj/request/JavaBinUpdateRequestCodec.java   |  1 +
 .../org/apache/solr/common/util/JavaBinCodec.java  | 30 ++++++++++++++--
 .../solr/common/util/TestFastJavabinDecoder.java   |  8 ++---
 .../apache/solr/common/util/TestJavaBinCodec.java  | 40 +++++++++++++---------
 5 files changed, 60 insertions(+), 23 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 35447fc2fcb..2813b433806 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -369,6 +369,10 @@ Other Changes
 * SOLR-17625: Replaced NamedList.findRecursive usages with _get, which can do 
Map traversal, and
   thus makes it easier to transition intermediate NamedLists to Maps. (Gaurav 
Tuli)
 
+* SOLR-17635: javabin format: provide option to decode maps as 
SimpleOrderedMap (a NamedList & Map)
+  instead of LinkedHashMap.  Intended to aid in 10.x compatibility.  Enable 
via sys prop: solr.solrj.javabin.readMapAsNamedList=true
+  (Renato Haeberli, David Smiley)
+
 ==================  9.8.1 ==================
 Bug Fixes
 ---------------------
diff --git 
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
 
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
index 782f441eb19..6ce10ef381b 100644
--- 
a/solr/solrj/src/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
+++ 
b/solr/solrj/src/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
@@ -106,6 +106,7 @@ public class JavaBinUpdateRequestCodec {
 
     // reads documents, sending to handler.  Other data is in NamedList
     try (var codec = new StreamingCodec(handler)) {
+      codec.readMapAsNamedList(false);
       namedList = codec.unmarshal(is);
     }
 
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/JavaBinCodec.java 
b/solr/solrj/src/java/org/apache/solr/common/util/JavaBinCodec.java
index 7373632da28..a19896ff2b3 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/JavaBinCodec.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/JavaBinCodec.java
@@ -124,6 +124,9 @@ public class JavaBinCodec implements PushWriter {
   private boolean alreadyUnmarshalled;
   protected boolean readStringAsCharSeq = false;
 
+  private boolean readMapAsNamedList =
+      EnvUtils.getPropertyAsBool("solr.solrj.javabin.readMapAsNamedList", 
false);
+
   public JavaBinCodec() {
     resolver = null;
     writableDocFields = null;
@@ -848,9 +851,14 @@ public class JavaBinCodec implements PushWriter {
     return size < 0 ? new LinkedHashMap<>() : 
CollectionUtil.newLinkedHashMap(size);
   }
 
-  public Map<Object, Object> readMap(DataInputInputStream dis) throws 
IOException {
+  public Map<?, Object> readMap(DataInputInputStream dis) throws IOException {
     int sz = readVInt(dis);
-    return readMap(dis, sz);
+
+    if (readMapAsNamedList) {
+      return readMapAsSimpleOrderedMapForStringKeys(dis, sz);
+    } else {
+      return readMap(dis, sz);
+    }
   }
 
   protected Map<Object, Object> readMap(DataInputInputStream dis, int sz) 
throws IOException {
@@ -863,6 +871,17 @@ public class JavaBinCodec implements PushWriter {
     return m;
   }
 
+  protected Map<?, Object> 
readMapAsSimpleOrderedMapForStringKeys(DataInputInputStream dis, int sz)
+      throws IOException {
+    SimpleOrderedMap<Object> entries = new SimpleOrderedMap<>(sz);
+    for (int i = 0; i < sz; i++) {
+      Object key = readVal(dis);
+      Object val = readVal(dis);
+      entries.add((String) key, val); // using NL.add() since key won't repeat
+    }
+    return entries;
+  }
+
   public final ItemWriter itemWriter =
       new ItemWriter() {
         @Override
@@ -1436,4 +1455,11 @@ public class JavaBinCodec implements PushWriter {
       daos.flushBuffer();
     }
   }
+
+  /**
+   * If set, Maps will be deserialized as {@link SimpleOrderedMap} instead of 
{@link LinkedHashMap}
+   */
+  public void readMapAsNamedList(boolean readMapAsNamedList) {
+    this.readMapAsNamedList = readMapAsNamedList;
+  }
 }
diff --git 
a/solr/solrj/src/test/org/apache/solr/common/util/TestFastJavabinDecoder.java 
b/solr/solrj/src/test/org/apache/solr/common/util/TestFastJavabinDecoder.java
index 9759fd84b92..6c572f91fcd 100644
--- 
a/solr/solrj/src/test/org/apache/solr/common/util/TestFastJavabinDecoder.java
+++ 
b/solr/solrj/src/test/org/apache/solr/common/util/TestFastJavabinDecoder.java
@@ -91,8 +91,8 @@ public class TestFastJavabinDecoder extends SolrTestCaseJ4 {
                 .withInputStream(new FastInputStream(null, baos.getbuf(), 0, 
baos.size()))
                 .decode(FastJavaBinDecoder.getEntryListener());
     assertEquals(
-        Utils.writeJson(m2, new StringWriter(), true).toString(),
-        Utils.writeJson(fastMap, new StringWriter(), true).toString());
+        Utils.writeJson(m2, new StringWriter(), false).toString(),
+        Utils.writeJson(fastMap, new StringWriter(), false).toString());
 
     @SuppressWarnings({"unchecked", "rawtypes"})
     Object newMap =
@@ -125,8 +125,8 @@ public class TestFastJavabinDecoder extends SolrTestCaseJ4 {
                 });
     ((Map) m2.get("mapk")).remove("k2");
     assertEquals(
-        Utils.writeJson(m2, new StringWriter(), true).toString(),
-        Utils.writeJson(newMap, new StringWriter(), true).toString());
+        Utils.writeJson(m2, new StringWriter(), false).toString(),
+        Utils.writeJson(newMap, new StringWriter(), false).toString());
   }
 
   public void testFastJavabinStreamingDecoder() throws IOException {
diff --git 
a/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java 
b/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
index eb9cc217113..52d5cf1e3c9 100644
--- a/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
+++ b/solr/solrj/src/test/org/apache/solr/common/util/TestJavaBinCodec.java
@@ -69,6 +69,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
         jbcO.marshal(s, os);
         try (JavaBinCodec jbcI = new JavaBinCodec();
             ByteArrayInputStream is = new 
ByteArrayInputStream(os.toByteArray())) {
+          jbcI.readMapAsNamedList(false);
           Object o = jbcI.unmarshal(is);
           assertEquals(s, o);
         }
@@ -86,6 +87,17 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
     compareObjects((List) getObject(getBytes(types, true)), (List) types);
   }
 
+  public void testReadMap() throws Exception {
+    Map<String, String> types = new HashMap<>();
+    types.put("1", "one");
+
+    byte[] bytes = getBytes(types, true);
+    Object result = getObjectWithMapAsNl(bytes, true);
+
+    assertTrue(result instanceof SimpleOrderedMap);
+    assertEquals("one", ((SimpleOrderedMap<?>) result).get("1"));
+  }
+
   public static SolrDocument generateSolrDocumentWithChildDocs() {
     SolrDocument parentDocument = new SolrDocument();
     parentDocument.addField("id", "1");
@@ -162,11 +174,6 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
 
     types.add(new byte[] {1, 2, 3, 4, 5});
 
-    // TODO?
-    // List<String> list = new ArrayList<String>();
-    // list.add("one");
-    // types.add(list.iterator());
-
     types.add((byte) 15); // END
 
     SolrInputDocument idoc = new SolrInputDocument();
@@ -211,6 +218,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
                 return super.readIterator(fis);
               }
             }; ) {
+      javabin.readMapAsNamedList(false);
       @SuppressWarnings({"unchecked"})
       List<Object> unmarshalledObj = (List<Object>) javabin.unmarshal(is);
       List<Object> matchObj = generateAllDataTypes();
@@ -285,6 +293,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
         ByteArrayOutputStream os = new ByteArrayOutputStream()) {
 
       Object data = generateAllDataTypes();
+      javabin.readMapAsNamedList(false);
       javabin.marshal(data, os);
       byte[] newFormatBytes = os.toByteArray();
 
@@ -294,7 +303,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
         for (int i = 1;
             i < currentFormatBytes.length;
             i++) { // ignore the first byte. It is version information
-          assertEquals(newFormatBytes[i], currentFormatBytes[i]);
+          assertEquals("for i:" + i, newFormatBytes[i], currentFormatBytes[i]);
         }
       }
     }
@@ -383,6 +392,7 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
     try (InputStream is = getClass().getResourceAsStream(fileName)) {
       try (DataInputInputStream dis = new FastInputStream(is)) {
         try (JavaBinCodec javabin = new JavaBinCodec()) {
+          javabin.readMapAsNamedList(false);
           return javabin.readMapEntry(dis);
         }
       }
@@ -410,12 +420,18 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
     }
   }
 
-  private static Object getObject(byte[] bytes) throws IOException {
+  private static Object getObjectWithMapAsNl(byte[] bytes, boolean 
mapAsNamedList)
+      throws IOException {
     try (JavaBinCodec jbc = new JavaBinCodec()) {
+      jbc.readMapAsNamedList(mapAsNamedList);
       return jbc.unmarshal(new ByteArrayInputStream(bytes));
     }
   }
 
+  private static Object getObject(byte[] bytes) throws IOException {
+    return getObjectWithMapAsNl(bytes, false);
+  }
+
   @Test
   public void testResponseChildDocuments() throws IOException {
     SolrDocument result =
@@ -582,16 +598,6 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 {
     System.out.println("Free Memory:" + runtime.freeMemory() / mb);
   }
 
-  public static void main(String[] args) throws IOException {
-    TestJavaBinCodec test = new TestJavaBinCodec();
-    test.genBinaryFiles();
-    //    try {
-    //      doDecodePerf(args);
-    //    } catch (Exception e) {
-    //      throw new RuntimeException(e);
-    //    }
-  }
-
   // common-case ascii
   static String str(Random r, int sz) {
     StringBuilder sb = new StringBuilder(sz);

Reply via email to