From 4d07930143f9cc33417a3a4daf61c87975761180 Mon Sep 17 00:00:00 2001 From: RuedigerMoeller Date: Mon, 31 Jul 2017 15:14:46 +0200 Subject: [PATCH] fixes, bump version --- pom.xml | 2 +- .../serialization/FSTConfiguration.java | 23 ++- .../nustaq/serialization/FSTObjectInput.java | 4 + .../nustaq/serialization/FSTObjectOutput.java | 15 +- .../serialization/coders/FSTJsonEncoder.java | 9 ++ src/test/json/StringEnc.java | 16 ++ src/test/offheap/StringOffHeapTest.java | 2 +- src/test/ser/RawMemTest.java | 15 -- src/test/ser/serializers/Github204.java | 142 ++++++++++++++++++ 9 files changed, 201 insertions(+), 27 deletions(-) create mode 100644 src/test/ser/serializers/Github204.java diff --git a/pom.xml b/pom.xml index 84b1cce6..efbab67d 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ 4.0.0 de.ruedigermoeller fst - 2.51 + 2.52 bundle A fast java serialization drop in-replacement and some serialization based utils such as Structs and OffHeap Memory. diff --git a/src/main/java/org/nustaq/serialization/FSTConfiguration.java b/src/main/java/org/nustaq/serialization/FSTConfiguration.java index fa8a5422..42289f4f 100644 --- a/src/main/java/org/nustaq/serialization/FSTConfiguration.java +++ b/src/main/java/org/nustaq/serialization/FSTConfiguration.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.SerializableString; import com.fasterxml.jackson.core.io.IOContext; +import com.fasterxml.jackson.core.json.JsonWriteContext; import com.fasterxml.jackson.core.json.UTF8JsonGenerator; import com.fasterxml.jackson.core.util.DefaultPrettyPrinter; import org.nustaq.offheap.bytez.onheap.HeapBytez; @@ -36,12 +37,14 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; import java.util.*; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicBoolean; + /** * Created with IntelliJ IDEA. * User: ruedi @@ -257,7 +260,10 @@ public static FSTConfiguration createJsonNoRefConfiguration() { /** * create a json conf with given attributes. Note that shared refs = true for jason might be not as stable as for binary encodings * as fst relies on stream positions to identify objects within a given input, so any inbetween formatting will break proper reference - * resolution + * resolution. + * + * WARNING: use of sharedrefs = true is Deprecated as its flakey + * * @param prettyPrint * @param shareReferences * @return @@ -269,6 +275,10 @@ public static FSTConfiguration createJsonConfiguration(boolean prettyPrint, bool return createJsonConfiguration(prettyPrint,shareReferences,null); } + public static FSTConfiguration createJsonConfiguration() { + return createJsonConfiguration(false,false); + } + protected static FSTConfiguration createJsonConfiguration(boolean prettyPrint, boolean shareReferences, ConcurrentHashMap shared ) { if ( prettyPrint && shareReferences ) { throw new RuntimeException("cannot use prettyPrint with shared refs to 'true'. Set shareRefs to false."); @@ -467,7 +477,7 @@ protected static FSTConfiguration initDefaultFstConfigurationInternal(FSTConfigu // for most cases don't register for subclasses as in many cases we'd like to fallback to JDK implementation // (e.g. TreeMap) in order to guarantee complete serialization reg.putSerializer(ArrayList.class, new FSTArrayListSerializer(), false); - reg.putSerializer(Vector.class, new FSTCollectionSerializer(), false); + reg.putSerializer(Vector.class, new FSTCollectionSerializer(), true); reg.putSerializer(LinkedList.class, new FSTCollectionSerializer(), false); // subclass should register manually reg.putSerializer(HashSet.class, new FSTCollectionSerializer(), false); // subclass should register manually reg.putSerializer(HashMap.class, new FSTMapSerializer(), false); // subclass should register manually @@ -923,6 +933,8 @@ public FSTObjectInput getObjectInputCopyFrom( byte arr[],int off, int len ) { protected FSTObjectInput getIn() { FSTObjectInput fstObjectInput = (FSTObjectInput) streamCoderFactory.getInput().get(); + if ( fstObjectInput != null && fstObjectInput.isClosed() ) + fstObjectInput = null; if ( fstObjectInput == null ) { streamCoderFactory.getInput().set(new FSTObjectInput(this)); return getIn(); @@ -1191,13 +1203,8 @@ public String asJsonString(Object o) { if ( getCoderSpecific() instanceof JsonFactory == false ) { return "can be called on JsonConfiguration only"; } else { - try { - return new String(asByteArray(o),"UTF-8"); - } catch (UnsupportedEncodingException e) { - FSTUtil.rethrow(e); - } + return new String(asByteArray(o), StandardCharsets.UTF_8); } - return null; } /** diff --git a/src/main/java/org/nustaq/serialization/FSTObjectInput.java b/src/main/java/org/nustaq/serialization/FSTObjectInput.java index 36c4950b..0f177921 100644 --- a/src/main/java/org/nustaq/serialization/FSTObjectInput.java +++ b/src/main/java/org/nustaq/serialization/FSTObjectInput.java @@ -147,6 +147,10 @@ protected void setCodec(FSTDecoder codec) { this.codec = codec; } + public boolean isClosed() { + return closed; + } + protected static class CallbackEntry { ObjectInputValidation cb; int prio; diff --git a/src/main/java/org/nustaq/serialization/FSTObjectOutput.java b/src/main/java/org/nustaq/serialization/FSTObjectOutput.java index d5852d13..66bfa806 100644 --- a/src/main/java/org/nustaq/serialization/FSTObjectOutput.java +++ b/src/main/java/org/nustaq/serialization/FSTObjectOutput.java @@ -451,10 +451,21 @@ protected FSTClazzInfo writeObjectWithContext(FSTClazzInfo.FSTFieldInfo referenc return originalInfo; } } + if (! writeObjectHeader(serializationInfo, referencee, toWrite) ) { // skip in case codec can write object as primitive - defaultWriteObject(toWrite, serializationInfo); - if ( serializationInfo.isExternalizable() ) + ser = serializationInfo.getSer(); + if ( ser == null ) { + defaultWriteObject(toWrite, serializationInfo); + if ( serializationInfo.isExternalizable() ) + getCodec().externalEnd(serializationInfo); + } else { + // handle edge case: there is a serializer registered for replaced class + // copied from below :( + int pos = getCodec().getWritten(); + // write object depending on type (custom, externalizable, serializable/java, default) + ser.writeObject(this, toWrite, serializationInfo, referencee, pos); getCodec().externalEnd(serializationInfo); + } } return originalInfo; } else { // object has custom serializer diff --git a/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java b/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java index f54fd7bf..eb37318f 100644 --- a/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java +++ b/src/main/java/org/nustaq/serialization/coders/FSTJsonEncoder.java @@ -3,7 +3,9 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonStreamContext; +import com.fasterxml.jackson.core.ObjectCodec; import com.fasterxml.jackson.core.io.SerializedString; +import com.fasterxml.jackson.core.json.JsonWriteContext; import org.nustaq.serialization.*; import org.nustaq.serialization.util.FSTOutputStream; import org.nustaq.serialization.util.FSTUtil; @@ -168,6 +170,13 @@ public void close() throws IOException { @Override public void reset(byte[] outbytes) { + if ( gen != null ) { + try { + createGenerator(); + } catch (Exception e) { + FSTUtil.rethrow(e); + } + } if (outbytes==null) { out.reset(); } else { diff --git a/src/test/json/StringEnc.java b/src/test/json/StringEnc.java index 8844286e..5b86c9a0 100644 --- a/src/test/json/StringEnc.java +++ b/src/test/json/StringEnc.java @@ -31,4 +31,20 @@ public void testStringenc() throws UnsupportedEncodingException { Assert.assertTrue(x.equals("ÄÖasdß")); } + static class PJ implements Serializable { + int a = 10; + } + + @Test + public void testLeadingSpaceBug() { + FSTConfiguration fst = FSTConfiguration.createJsonConfiguration(); + PJ pojo = new PJ(); + String x = fst.asJsonString(pojo); + System.out.println(x); + String x1 = fst.asJsonString(pojo); + System.out.println(x1); + Assert.assertTrue(x.equals(x1)); + + } + } diff --git a/src/test/offheap/StringOffHeapTest.java b/src/test/offheap/StringOffHeapTest.java index 1b62f3eb..55112805 100644 --- a/src/test/offheap/StringOffHeapTest.java +++ b/src/test/offheap/StringOffHeapTest.java @@ -148,7 +148,7 @@ public void hardcore() throws Exception { FSTCoder coder = createCoder(); coder.getConf().registerClass(TestRec.class); - int count = 5; + int count = 2; // while (true) while (count-- > 0) { diff --git a/src/test/ser/RawMemTest.java b/src/test/ser/RawMemTest.java index f39ab6b5..6121c5fc 100644 --- a/src/test/ser/RawMemTest.java +++ b/src/test/ser/RawMemTest.java @@ -49,18 +49,12 @@ public void test() { System.out.println("binary"); deser = smallBench(conf, original, deser); deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); assertTrue(DeepEquals.deepEquals(original, deser)); System.out.println("default"); conf = FSTConfiguration.createDefaultConfiguration(); deser = smallBench(conf, original, deser); deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); - deser = smallBench(conf, original, deser); assertTrue(DeepEquals.deepEquals(original, deser)); System.out.println("Default LEN:"+FSTConfiguration.createDefaultConfiguration().asByteArray(original).length); @@ -99,8 +93,6 @@ public void testOffHeapCoder0( boolean shared ) throws Exception { MallocBytezAllocator alloc = new MallocBytezAllocator(); MallocBytez bytez = (MallocBytez) alloc.alloc(1000 * 1000); - ohbench(original, coder, bytez); - ohbench(original, coder, bytez); ohbench(original, coder, bytez); ohbench(original, coder, bytez); Object deser = ohbench(original, coder, bytez); @@ -109,8 +101,6 @@ public void testOffHeapCoder0( boolean shared ) throws Exception { System.out.println("-----"); ohbench(smallClazz, coder, bytez); ohbench(smallClazz, coder, bytez); - ohbench(smallClazz, coder, bytez); - ohbench(smallClazz, coder, bytez); deser = ohbench(smallClazz, coder, bytez); assertTrue(DeepEquals.deepEquals(smallClazz, deser)); @@ -158,8 +148,6 @@ public void testOnHeapCoder0(boolean shared) throws Exception { Object deser = coder.toObject(arr, 0, (int) arr.length); assertTrue(DeepEquals.deepEquals(deser,original)); - onhbench(original, coder, arr, 0); - onhbench(original, coder, arr, 0); onhbench(original, coder, arr, 0); onhbench(original, coder, arr, 0); deser = onhbench(original, coder, arr, 0); @@ -168,9 +156,6 @@ public void testOnHeapCoder0(boolean shared) throws Exception { System.out.println("-----"); deser = onhbench(smallClazz, coder, arr, 0); deser = onhbench(smallClazz, coder, arr, 0); - deser = onhbench(smallClazz, coder, arr, 0); - deser = onhbench(smallClazz, coder, arr, 0); - deser = onhbench(smallClazz, coder, arr, 0); assertTrue(DeepEquals.deepEquals(smallClazz, deser)); boolean lenEx = false; diff --git a/src/test/ser/serializers/Github204.java b/src/test/ser/serializers/Github204.java new file mode 100644 index 00000000..c39e2bb1 --- /dev/null +++ b/src/test/ser/serializers/Github204.java @@ -0,0 +1,142 @@ +package ser.serializers; + +import org.junit.Test; +import org.nustaq.serialization.FSTConfiguration; +import org.nustaq.serialization.FSTObjectInput; +import org.nustaq.serialization.FSTObjectOutput; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * Created by ruedi on 31.07.17. + */ +public class Github204 { + + @Test + public void testMapWriteReplace() throws Exception { + Map map = new MyMap<>(); + map.put("value", 1234.5); + + Map map1 = new MyMap<>(); + map1.put("othervalue", 5678.9); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + FSTObjectOutput out = new FSTObjectOutput(buf, getTestConfiguration()); + out.writeObject(map); + out.writeObject(map1); + out.writeObject("Ensure Stream is not corrupted"); + out.close(); + + FSTObjectInput in = getTestConfiguration().getObjectInput(new ByteArrayInputStream(buf.toByteArray())); + Map res = (Map) in.readObject(); + Map res1 = (Map) in.readObject(); + in.close(); + + assertEquals(LinkedHashMap.class, res.getClass()); + assertEquals(1, res.size()); + assertEquals(1234.5, res.get("value")); + assertEquals(LinkedHashMap.class, res1.getClass()); + assertEquals(1, res1.size()); + assertEquals(5678.9, res1.get("othervalue")); + } + + private FSTConfiguration getTestConfiguration() { + return FSTConfiguration.createDefaultConfiguration(); + } + + public static class MyMap implements Map, Serializable { + private final Map data; + + public MyMap() { + this(new HashMap()); + } + + + public MyMap(Map data) { + this.data = data; + } + + @Override + public int size() { + return data.size(); + } + + @Override + public boolean isEmpty() { + return data.isEmpty(); + } + + @Override + public boolean containsKey(Object key) { + return data.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + return data.containsValue(value); + } + + @Override + public V get(Object key) { + return data.get(key); + } + + @Override + public V put(K key, V value) { + return data.put(key, value); + } + + @Override + public V remove(Object key) { + return data.remove(key); + } + + @Override + public void putAll(Map m) { + data.putAll(m); + } + + @Override + public void clear() { + data.clear(); + } + + @Override + public Set keySet() { + return data.keySet(); + } + + @Override + public Collection values() { + return data.values(); + } + + @Override + public Set> entrySet() { + return data.entrySet(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + MyMap myMap = (MyMap) o; + return Objects.equals(data, myMap.data); + } + + @Override + public int hashCode() { + return Objects.hash(data); + } + + private Object writeReplace() throws ObjectStreamException { + return new LinkedHashMap(this); + } + } +}