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 3e83f24a32f..c17e4bceb8c 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 @@ -510,6 +510,7 @@ public class JavaBinCodec { public Map.Entry readMapEntry(DataInputInputStream dis) throws IOException { final Object key = readVal(dis); final Object value = readVal(dis); + //return new AbstractMap.SimpleImmutableEntry(key, value); return new Map.Entry() { @Override @@ -521,7 +522,7 @@ public class JavaBinCodec { public Object getValue() { return value; } - + @Override public String toString() { return "MapEntry[" + key.toString() + ":" + value.toString() + "]"; @@ -530,7 +531,28 @@ public class JavaBinCodec { @Override public Object setValue(Object value) { throw new UnsupportedOperationException(); - }}; + } + + @Override + public int hashCode() { + int result = 31; + result *=31 + getKey().hashCode(); + result *=31 + getValue().hashCode(); + return result; + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(!(obj instanceof Entry)) { + return false; + } + Map.Entry entry = (Entry) obj; + return (this.getKey().equals(entry.getKey()) && this.getValue().equals(entry.getValue())); + } + }; } /** diff --git a/solr/solrj/src/test-files/solrj/javabin_backcompat.bin b/solr/solrj/src/test-files/solrj/javabin_backcompat.bin new file mode 100644 index 00000000000..6e9d32ff78f Binary files /dev/null and b/solr/solrj/src/test-files/solrj/javabin_backcompat.bin differ 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 1f7eebf3cf8..d0a39e51eaa 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 @@ -17,14 +17,34 @@ package org.apache.solr.common.util; * limitations under the License. */ -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; - +import org.apache.commons.io.IOUtils; import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.util.TestUtil; +import org.apache.solr.common.EnumFieldValue; +import org.apache.solr.common.SolrDocument; +import org.apache.solr.common.SolrDocumentList; +import org.apache.solr.common.SolrInputDocument; +import org.junit.Test; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; public class TestJavaBinCodec extends LuceneTestCase { - + + private final String BIN_FILE_LOCATION = "./solr/solrj/src/test-files/solrj/javabin_backcompat.bin"; + public void testStrings() throws Exception { JavaBinCodec javabin = new JavaBinCodec(); for (int i = 0; i < 10000*RANDOM_MULTIPLIER; i++) { @@ -36,4 +56,160 @@ public class TestJavaBinCodec extends LuceneTestCase { assertEquals(s, o); } } + + private List generateAllDataTypes() { + List types = new ArrayList<>(); + + types.add(null); //NULL + types.add(true); + types.add(false); + types.add((byte) 1); + types.add((short) 2); + types.add((double) 3); + + types.add(-4); + types.add(4); + types.add(42); + + types.add((long) -5); + types.add((long) 5); + types.add((long) 50); + + types.add((float) 6); + types.add(new Date(0)); + + Map map = new HashMap<>(); + map.put(1, 2); + types.add(map); + + SolrDocument doc = new SolrDocument(); + doc.addField("foo", "bar"); + types.add(doc); + + SolrDocumentList solrDocs = new SolrDocumentList(); + solrDocs.setMaxScore(1.0f); + solrDocs.setNumFound(1); + solrDocs.setStart(0); + solrDocs.add(0, doc); + types.add(solrDocs); + + types.add(new byte[] {1,2,3,4,5}); + + List list = new ArrayList(); + list.add("one"); + //types.add(list.iterator()); + + types.add((byte) 15); //END + + SolrInputDocument idoc = new SolrInputDocument(); + idoc.addField("foo", "bar"); + types.add(idoc); + + SolrInputDocument parentDoc = new SolrInputDocument(); + parentDoc.addField("foo", "bar"); + SolrInputDocument childDoc = new SolrInputDocument(); + childDoc.addField("foo", "bar"); + parentDoc.addChildDocument(childDoc); + types.add(parentDoc); + + types.add(new EnumFieldValue(1, "foo")); + + types.add(map.entrySet().iterator().next()); //Map.Entry + + types.add((byte) (1 << 5)); //TAG_AND_LEN + + types.add("foo"); + types.add(1); + types.add((long) 2); + + SimpleOrderedMap simpleOrderedMap = new SimpleOrderedMap(); + simpleOrderedMap.add("bar", "barbar"); + types.add(simpleOrderedMap); + + NamedList nl = new NamedList<>(); + nl.add("foo", "barbar"); + types.add(nl); + + return types; + } + + @Test + public void testBackCompat() { + List iteratorAsList = null; + JavaBinCodec javabin = new JavaBinCodec(){ + @Override + public List readIterator(DataInputInputStream fis) throws IOException { + return super.readIterator(fis); + } + }; + try { + InputStream is = getClass().getResourceAsStream("/solrj/javabin_backcompat.bin"); + List unmarshaledObj = (List) javabin.unmarshal(is); + List matchObj = generateAllDataTypes(); + + assertEquals(unmarshaledObj.size(), matchObj.size()); + for(int i=0; i < unmarshaledObj.size(); i++) { + + if(unmarshaledObj.get(i) instanceof byte[] && matchObj.get(i) instanceof byte[]) { + byte[] b1 = (byte[]) unmarshaledObj.get(i); + byte[] b2 = (byte[]) matchObj.get(i); + assertTrue(Arrays.equals(b1, b2)); + + } else { + assertEquals(unmarshaledObj.get(i), matchObj.get(i)); + } + + } + } catch (IOException e) { + fail(e.getMessage()); + } + + } + + @Test + public void testForwardCompat() { + JavaBinCodec javabin = new JavaBinCodec(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + Object data = generateAllDataTypes(); + try { + javabin.marshal(data, os); + byte[] newFormatBytes = os.toByteArray(); + + InputStream is = getClass().getResourceAsStream("/solrj/javabin_backcompat.bin"); + byte[] currentFormatBytes = IOUtils.toByteArray(is); + + for (int i = 1; i < currentFormatBytes.length; i++) {//ignore the first byte. It is version information + assertEquals(currentFormatBytes[i], newFormatBytes[i]); + } + + } catch (IOException e) { + fail(e.getMessage()); + } + + } + + public void genBinaryFile() { + JavaBinCodec javabin = new JavaBinCodec(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + Object data = generateAllDataTypes(); + try { + javabin.marshal(data, os); + byte[] out = os.toByteArray(); + FileOutputStream fs = new FileOutputStream(new File( BIN_FILE_LOCATION )); + BufferedOutputStream bos = new BufferedOutputStream(fs); + bos.write(out); + bos.close(); + } catch (IOException e) { + //TODO fail test? + } + + } + + public static void main(String[] args) { + TestJavaBinCodec test = new TestJavaBinCodec(); + test.genBinaryFile(); + } + }