java_gen.PrimitiveSinkUtils: add support for putting nullable Strings, better support for null

Based on a conversation with @rlane, prepend optional entries with a
presence bit + length instead of the null-byte delimitation.
diff --git a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtils.java b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtils.java
index 0f7400e..28eb3a4 100644
--- a/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtils.java
+++ b/java_gen/pre-written/src/main/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtils.java
@@ -16,20 +16,33 @@
 public class PrimitiveSinkUtils {
     private PrimitiveSinkUtils() {}
 
-    /** puts a nullable element into a primitive sink. The entry is terminated by a null byte
-     *  to disambiguate null elements.
+    /** puts a nullable String into a primitive sink. The entry is prepended by a 'presence'
+     *  boolean bit and the string length;
+     *
+     *
+     * @param sink the sink to put the object
+     * @param nullableObj the potentially null string to put in the sink
+     */
+    public static void putNullableStringTo(PrimitiveSink sink,
+            @Nullable CharSequence nullableChars) {
+
+        sink.putBoolean(nullableChars != null);
+        if(nullableChars != null) {
+            sink.putInt(nullableChars.length());
+            sink.putUnencodedChars(nullableChars);
+        }
+    }
+
+    /** puts a nullable element into a primitive sink. The entry is prepended by a 'present' bit.
      *
      * @param sink the sink to put the object
      * @param nullableObj the nullable object
      */
     public static void putNullableTo(PrimitiveSink sink,
             @Nullable PrimitiveSinkable nullableObj) {
+        sink.putBoolean(nullableObj != null);
         if(nullableObj != null)
             nullableObj.putTo(sink);
-
-        // terminate this object representation by a null byte. this ensures that we get
-        // unique digests even if some values are null
-        sink.putByte((byte) 0);
     }
 
     /** puts the elements of a sorted set into the {@link PrimitiveSink}. Does not support null
@@ -40,6 +53,7 @@
      */
     public static void putSortedSetTo(PrimitiveSink sink,
             SortedSet<? extends PrimitiveSinkable> set) {
+        sink.putInt(set.size());
         for(PrimitiveSinkable e: set) {
             e.putTo(sink);
         }
@@ -53,6 +67,7 @@
      */
     public static void putListTo(PrimitiveSink sink,
             List<? extends PrimitiveSinkable> set) {
+        sink.putInt(set.size());
         for(PrimitiveSinkable e: set) {
             e.putTo(sink);
         }
diff --git a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java
index 5c2f9e6..f5bf3e4 100644
--- a/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java
+++ b/java_gen/pre-written/src/test/java/org/projectfloodlight/openflow/util/PrimitiveSinkUtilsTest.java
@@ -27,6 +27,23 @@
     }
 
     @Test
+    public void testPutNullableString() {
+        // test that these different invocations of putNullable
+        // differ pairwise
+        HashCode[] hs = new HashCode[] {
+                calcPutNullableString((String) null),
+                calcPutNullableString(""),
+                calcPutNullableString(null, null),
+                calcPutNullableString(null, ""),
+                calcPutNullableString("", null),
+                calcPutNullableString("a\0a", null),
+                calcPutNullableString(null, "a\0a"),
+        };
+
+        checkPairwiseDifferent(hs);
+    }
+
+    @Test
     public void testPutNullable() {
         // test that these different invocations of putNullable
         // differ pairwise
@@ -80,7 +97,15 @@
 
         assertThat(calcPutSortedSet(OFPort.of(1), OFPort.of(2)),
                 equalTo(calcPutSortedSet(OFPort.of(2), OFPort.of(1))));
-}
+    }
+
+    private HashCode calcPutNullableString(String... strings) {
+        Hasher h = hash.newHasher();
+        for(String s: strings) {
+            PrimitiveSinkUtils.putNullableStringTo(h, s);
+        }
+        return h.hash();
+    }
 
     private HashCode calcPutSortedSet(OFPort... ports) {
         Hasher h = hash.newHasher();