From d87d8da17d7067ac873a11ba748beb7d82beb95e Mon Sep 17 00:00:00 2001 From: Shalin Shekhar Mangar Date: Thu, 3 Mar 2016 18:06:04 +0530 Subject: [PATCH] * SOLR-7516: Improve javadocs for JavaBinCodec, ObjectResolver and enforce the single-usage policy This closes #17 --- solr/CHANGES.txt | 2 + .../org/apache/solr/search/CursorMark.java | 11 ++--- .../apache/solr/common/util/JavaBinCodec.java | 40 +++++++++++++++---- .../solr/common/util/TestJavaBinCodec.java | 5 +-- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index 11aab7f112c..3989a6b08a1 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -34,6 +34,8 @@ Optimizations Other Changes ---------------------- +* SOLR-7516: Improve javadocs for JavaBinCodec, ObjectResolver and enforce the single-usage policy. + (Jason Gerlowski, Benoit Vanalderweireldt, shalin) ================== 6.0.0 ================== diff --git a/solr/core/src/java/org/apache/solr/search/CursorMark.java b/solr/core/src/java/org/apache/solr/search/CursorMark.java index 9d2e20dd4d3..633028689c7 100644 --- a/solr/core/src/java/org/apache/solr/search/CursorMark.java +++ b/solr/core/src/java/org/apache/solr/search/CursorMark.java @@ -61,11 +61,6 @@ public final class CursorMark { */ private List values = null; - /** - * for serializing this CursorMark as a String - */ - private final JavaBinCodec codec = new JavaBinCodec(); - /** * Generates an empty CursorMark bound for use with the * specified schema and {@link SortSpec}. @@ -190,7 +185,7 @@ public final class CursorMark { final byte[] rawData = Base64.base64ToByteArray(serialized); ByteArrayInputStream in = new ByteArrayInputStream(rawData); try { - pieces = (List) codec.unmarshal(in); + pieces = (List) new JavaBinCodec().unmarshal(in); boolean b = false; for (Object o : pieces) { if (o instanceof BytesRefBuilder || o instanceof BytesRef || o instanceof String) { @@ -199,7 +194,7 @@ public final class CursorMark { } if (b) { in.reset(); - pieces = (List) codec.unmarshal(in); + pieces = (List) new JavaBinCodec().unmarshal(in); } } finally { in.close(); @@ -267,7 +262,7 @@ public final class CursorMark { try { ByteArrayOutputStream out = new ByteArrayOutputStream(256); try { - codec.marshal(marshalledValues, out); + new JavaBinCodec().marshal(marshalledValues, out); byte[] rawData = out.toByteArray(); return Base64.byteArrayToBase64(rawData, 0, rawData.length); } finally { 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 b90fb7ea1dd..63c1b282a15 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 @@ -40,14 +40,19 @@ import org.apache.solr.common.SolrInputField; import org.noggit.CharArr; /** - * The class is designed to optimaly serialize/deserialize any supported types in Solr response. As we know there are only a limited type of - * items this class can do it with very minimal amount of payload and code. There are 15 known types and if there is an - * object in the object tree which does not fall into these types, It must be converted to one of these. Implement an - * ObjectResolver and pass it over It is expected that this class is used on both end of the pipes. The class has one - * read method and one write method for each of the datatypes + * Defines a space-efficient serialization/deserialization format for transferring data. *

- * Note -- Never re-use an instance of this class for more than one marshal or unmarshall operation. Always create a new - * instance. + * JavaBinCodec has built in support many commonly used types. This includes primitive types (boolean, byte, + * short, double, int, long, float), common Java containers/utilities (Date, Map, Collection, Iterator, String, + * Object[], byte[]), and frequently used Solr types ({@link NamedList}, {@link SolrDocument}, + * {@link SolrDocumentList}). Each of the above types has a pair of associated methods which read and write + * that type to a stream. + *

+ * Classes that aren't supported natively can still be serialized/deserialized by providing + * an {@link JavaBinCodec.ObjectResolver} object that knows how to work with the unsupported class. + * This allows {@link JavaBinCodec} to be used to marshall/unmarshall arbitrary content. + *

+ * NOTE -- {@link JavaBinCodec} instances cannot be reused for more than one marshall or unmarshall operation. */ public class JavaBinCodec { @@ -94,6 +99,8 @@ public class JavaBinCodec { protected FastOutputStream daos; private StringCache stringCache; private WritableDocFields writableDocFields; + private boolean alreadyMarshalled; + private boolean alreadyUnmarshalled; public JavaBinCodec() { resolver =null; @@ -119,12 +126,14 @@ public class JavaBinCodec { } public void marshal(Object nl, OutputStream os) throws IOException { + assert !alreadyMarshalled; init(FastOutputStream.wrap(os)); try { daos.writeByte(VERSION); writeVal(nl); } finally { daos.flushBuffer(); + alreadyMarshalled = true; } } @@ -136,12 +145,15 @@ public class JavaBinCodec { byte version; public Object unmarshal(InputStream is) throws IOException { + assert !alreadyUnmarshalled; FastInputStream dis = FastInputStream.wrap(is); version = dis.readByte(); if (version != VERSION) { throw new RuntimeException("Invalid version (expected " + VERSION + ", but " + version + ") or the data in not in 'javabin' format"); } + + alreadyUnmarshalled = true; return readVal(dis); } @@ -879,8 +891,20 @@ public class JavaBinCodec { } } - + /** + * Allows extension of {@link JavaBinCodec} to support serialization of arbitrary data types. + *

+ * Implementors of this interface write a method to serialize a given object using an existing {@link JavaBinCodec} + */ public static interface ObjectResolver { + /** + * Examine and attempt to serialize the given object, using a {@link JavaBinCodec} to write it to a stream. + * + * @param o the object that the caller wants serialized. + * @param codec used to actually serialize {@code o}. + * @return the object {@code o} itself if it could not be serialized, or {@code null} if the whole object was successfully serialized. + * @see JavaBinCodec + */ public Object resolve(Object o, JavaBinCodec codec) 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 b59eee9b00e..d5b9fdf99bc 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 @@ -53,13 +53,12 @@ public class TestJavaBinCodec extends SolrTestCaseJ4 { private final String BIN_FILE_LOCATION_CHILD_DOCS = "./solr/solrj/src/test-files/solrj/javabin_backcompat_child_docs.bin"; public void testStrings() throws Exception { - JavaBinCodec javabin = new JavaBinCodec(); for (int i = 0; i < 10000 * RANDOM_MULTIPLIER; i++) { String s = TestUtil.randomUnicodeString(random()); ByteArrayOutputStream os = new ByteArrayOutputStream(); - javabin.marshal(s, os); + new JavaBinCodec().marshal(s, os); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); - Object o = javabin.unmarshal(is); + Object o = new JavaBinCodec().unmarshal(is); assertEquals(s, o); } }