| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.pdx; |
| |
| import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.DataInput; |
| import java.io.DataInputStream; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.NotSerializableException; |
| import java.io.OutputStreamWriter; |
| import java.io.PrintWriter; |
| import java.nio.ByteBuffer; |
| import java.nio.file.Files; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.regex.Pattern; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import org.apache.geode.CopyHelper; |
| import org.apache.geode.DataSerializable; |
| import org.apache.geode.DataSerializer; |
| import org.apache.geode.DeltaTestImpl; |
| import org.apache.geode.ToDataException; |
| import org.apache.geode.cache.CacheFactory; |
| import org.apache.geode.cache.DiskStoreFactory; |
| import org.apache.geode.cache.Region; |
| import org.apache.geode.cache.RegionShortcut; |
| import org.apache.geode.internal.DSCODE; |
| import org.apache.geode.internal.HeapDataOutputStream; |
| import org.apache.geode.internal.PdxSerializerObject; |
| import org.apache.geode.internal.SystemAdmin; |
| import org.apache.geode.internal.Version; |
| import org.apache.geode.internal.cache.GemFireCacheImpl; |
| import org.apache.geode.internal.tcp.ByteBufferInputStream.ByteSourceFactory; |
| import org.apache.geode.internal.util.ArrayUtils; |
| import org.apache.geode.pdx.internal.DataSize; |
| import org.apache.geode.pdx.internal.PdxReaderImpl; |
| import org.apache.geode.pdx.internal.PdxType; |
| import org.apache.geode.pdx.internal.PdxWriterImpl; |
| import org.apache.geode.pdx.internal.PeerTypeRegistration; |
| import org.apache.geode.pdx.internal.TypeRegistry; |
| import org.apache.geode.test.junit.categories.SerializationTest; |
| |
| @Category({SerializationTest.class}) |
| public class PdxSerializableJUnitTest { |
| |
| private GemFireCacheImpl cache; |
| |
| @Before |
| public void setUp() { |
| // make it a loner |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").create(); |
| } |
| |
| @After |
| public void tearDown() { |
| this.cache.close(); |
| } |
| |
| private int getPdxTypeIdForClass(Class c) { |
| // here we are assuming Dsid == 0 |
| return this.cache.getPdxRegistry().getExistingTypeForClass(c).hashCode() |
| & PeerTypeRegistration.PLACE_HOLDER_FOR_TYPE_ID; |
| } |
| |
| private int getNumPdxTypes() { |
| return this.cache.getPdxRegistry().typeMap().size(); |
| } |
| |
| @Test |
| public void testNoDiskStore() throws Exception { |
| this.cache.close(); |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxPersistent(true) |
| .setPdxDiskStore("doesNotExist").create(); |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| PdxSerializable object = new SimpleClass(1, (byte) 5, null); |
| try { |
| DataSerializer.writeObject(object, out); |
| throw new Exception("expected PdxInitializationException"); |
| } catch (PdxInitializationException expected) { |
| } |
| } |
| |
| // for bugs 44271 and 44914 |
| @Test |
| public void testPdxPersistentKeys() throws Exception { |
| this.cache.close(); |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxPersistent(true) |
| .setPdxDiskStore("pdxDS").create(); |
| try { |
| DiskStoreFactory dsf = this.cache.createDiskStoreFactory(); |
| dsf.create("pdxDS"); |
| this.cache.createDiskStoreFactory().create("r2DS"); |
| Region r1 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT).create("r1"); |
| r1.put(new SimpleClass(1, (byte) 1), "1"); |
| r1.put(new SimpleClass(2, (byte) 2), "2"); |
| r1.put(new SimpleClass(1, (byte) 1), "1.2"); // so we have something to compact offline |
| Region r2 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT) |
| .setDiskStoreName("r2DS").create("r2"); |
| r2.put(new SimpleClass(1, (byte) 1), new SimpleClass(1, (byte) 1)); |
| r2.put(new SimpleClass(2, (byte) 2), new SimpleClass(2, (byte) 2)); |
| this.cache.close(); |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxPersistent(true) |
| .setPdxDiskStore("pdxDS").create(); |
| dsf = this.cache.createDiskStoreFactory(); |
| dsf.create("pdxDS"); |
| this.cache.createDiskStoreFactory().create("r2DS"); |
| r1 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT).create("r1"); |
| r2 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT).setDiskStoreName("r2DS") |
| .create("r2"); |
| assertEquals(true, r1.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r1.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(true, r2.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r2.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(new SimpleClass(1, (byte) 1), r2.get(new SimpleClass(1, (byte) 1))); |
| assertEquals(new SimpleClass(2, (byte) 2), r2.get(new SimpleClass(2, (byte) 2))); |
| this.cache.close(); |
| // use a cache.xml to recover |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").create(); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos), true); |
| pw.println("<?xml version=\"1.0\"?>"); |
| pw.println("<!DOCTYPE cache PUBLIC"); |
| pw.println(" \"-//GemStone Systems, Inc.//GemFire Declarative Caching 7.0//EN\""); |
| pw.println(" \"http://www.gemstone.com/dtd/cache7_0.dtd\">"); |
| pw.println("<cache>"); |
| pw.println(" <disk-store name=\"r2DS\"/>"); |
| pw.println(" <disk-store name=\"pdxDS\"/>"); |
| pw.println(" <pdx persistent=\"true\" disk-store-name=\"pdxDS\"/>"); |
| pw.println(" <region name=\"r1\" refid=\"LOCAL_PERSISTENT\"/>"); |
| pw.println(" <region name=\"r2\" refid=\"LOCAL_PERSISTENT\">"); |
| pw.println(" <region-attributes disk-store-name=\"r2DS\"/>"); |
| pw.println(" </region>"); |
| pw.println("</cache>"); |
| pw.close(); |
| byte[] bytes = baos.toByteArray(); |
| this.cache.loadCacheXml(new ByteArrayInputStream(bytes)); |
| r1 = this.cache.getRegion("/r1"); |
| r2 = this.cache.getRegion("/r2"); |
| assertEquals(true, r1.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r1.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(true, r2.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r2.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(new SimpleClass(1, (byte) 1), r2.get(new SimpleClass(1, (byte) 1))); |
| assertEquals(new SimpleClass(2, (byte) 2), r2.get(new SimpleClass(2, (byte) 2))); |
| this.cache.close(); |
| // make sure offlines tools work with disk store that has pdx keys |
| SystemAdmin.validateDiskStore("DEFAULT", "."); |
| SystemAdmin.compactDiskStore("DEFAULT", "."); |
| SystemAdmin.modifyDiskStore("DEFAULT", "."); |
| SystemAdmin.validateDiskStore("r2DS", "."); |
| SystemAdmin.compactDiskStore("r2DS", "."); |
| SystemAdmin.modifyDiskStore("r2DS", "."); |
| SystemAdmin.validateDiskStore("pdxDS", "."); |
| SystemAdmin.compactDiskStore("pdxDS", "."); |
| SystemAdmin.modifyDiskStore("pdxDS", "."); |
| } finally { |
| try { |
| this.cache.close(); |
| } finally { |
| Pattern pattern = Pattern.compile("BACKUP(DEFAULT|pdxDS|r2DS).*"); |
| File[] files = new File(".").listFiles((dir1, name) -> pattern.matcher(name).matches()); |
| if (files != null) { |
| for (File file : files) { |
| Files.delete(file.toPath()); |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testPdxPersistentKeysDefDS() throws Exception { |
| this.cache.close(); |
| this.cache = |
| (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxPersistent(true).create(); |
| try { |
| this.cache.createDiskStoreFactory().create("r2DS"); |
| Region r1 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT) |
| .setDiskStoreName("r2DS").create("r1"); |
| r1.put(new SimpleClass(1, (byte) 1), "1"); |
| r1.put(new SimpleClass(2, (byte) 2), "2"); |
| r1.put(new SimpleClass(1, (byte) 1), "1.2"); // so we have something to compact offline |
| Region r2 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT) |
| .setDiskStoreName("r2DS").create("r2"); |
| r2.put(new SimpleClass(1, (byte) 1), new SimpleClass(1, (byte) 1)); |
| r2.put(new SimpleClass(2, (byte) 2), new SimpleClass(2, (byte) 2)); |
| this.cache.close(); |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").setPdxPersistent(true) |
| .create(); |
| this.cache.createDiskStoreFactory().create("r2DS"); |
| r1 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT).setDiskStoreName("r2DS") |
| .create("r1"); |
| r2 = this.cache.createRegionFactory(RegionShortcut.LOCAL_PERSISTENT).setDiskStoreName("r2DS") |
| .create("r2"); |
| assertEquals(true, r1.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r1.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(true, r2.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r2.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(new SimpleClass(1, (byte) 1), r2.get(new SimpleClass(1, (byte) 1))); |
| assertEquals(new SimpleClass(2, (byte) 2), r2.get(new SimpleClass(2, (byte) 2))); |
| this.cache.close(); |
| // use a cache.xml to recover |
| this.cache = (GemFireCacheImpl) new CacheFactory().set(MCAST_PORT, "0").create(); |
| ByteArrayOutputStream baos = new ByteArrayOutputStream(); |
| PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos), true); |
| pw.println("<?xml version=\"1.0\"?>"); |
| pw.println("<!DOCTYPE cache PUBLIC"); |
| pw.println(" \"-//GemStone Systems, Inc.//GemFire Declarative Caching 7.0//EN\""); |
| pw.println(" \"http://www.gemstone.com/dtd/cache7_0.dtd\">"); |
| pw.println("<cache>"); |
| pw.println(" <disk-store name=\"r2DS\"/>"); |
| pw.println(" <pdx persistent=\"true\"/>"); |
| pw.println(" <region name=\"r1\" refid=\"LOCAL_PERSISTENT\">"); |
| pw.println(" <region-attributes disk-store-name=\"r2DS\"/>"); |
| pw.println(" </region>"); |
| pw.println(" <region name=\"r2\" refid=\"LOCAL_PERSISTENT\">"); |
| pw.println(" <region-attributes disk-store-name=\"r2DS\"/>"); |
| pw.println(" </region>"); |
| pw.println("</cache>"); |
| pw.close(); |
| byte[] bytes = baos.toByteArray(); |
| this.cache.loadCacheXml(new ByteArrayInputStream(bytes)); |
| r1 = this.cache.getRegion("/r1"); |
| r2 = this.cache.getRegion("/r2"); |
| assertEquals(true, r1.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r1.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(true, r2.containsKey(new SimpleClass(1, (byte) 1))); |
| assertEquals(true, r2.containsKey(new SimpleClass(2, (byte) 2))); |
| assertEquals(new SimpleClass(1, (byte) 1), r2.get(new SimpleClass(1, (byte) 1))); |
| assertEquals(new SimpleClass(2, (byte) 2), r2.get(new SimpleClass(2, (byte) 2))); |
| this.cache.close(); |
| // make sure offlines tools work with disk store that has pdx keys |
| SystemAdmin.validateDiskStore("DEFAULT", "."); |
| SystemAdmin.compactDiskStore("DEFAULT", "."); |
| SystemAdmin.modifyDiskStore("DEFAULT", "."); |
| SystemAdmin.validateDiskStore("r2DS", "."); |
| SystemAdmin.compactDiskStore("r2DS", "."); |
| SystemAdmin.modifyDiskStore("r2DS", "."); |
| } finally { |
| try { |
| this.cache.close(); |
| } finally { |
| Pattern pattern = Pattern.compile("BACKUP(DEFAULT|r2DS).*"); |
| File[] files = new File(".").listFiles((dir1, name) -> pattern.matcher(name).matches()); |
| if (files != null) { |
| for (File file : files) { |
| Files.delete(file.toPath()); |
| } |
| } |
| } |
| } |
| } |
| |
| @Test |
| public void testByteFormatForSimpleClass() throws Exception { |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| PdxSerializable object = new SimpleClass(1, (byte) 5, null); |
| DataSerializer.writeObject(object, out); |
| int typeId = getPdxTypeIdForClass(SimpleClass.class); |
| byte[] actual = out.toByteArray(); |
| byte[] expected = new byte[] {DSCODE.PDX.toByte(), // byte |
| 0, 0, 0, 4 + 1 + 1, // int - length of byte stream = 4(myInt) + 1(myByte) + 1 (myEnum) |
| (byte) (typeId >> 24), (byte) (typeId >> 16), (byte) (typeId >> 8), (byte) typeId, // int - |
| // typeId |
| 0, 0, 0, 1, // int - myInt = 1 |
| 5, // byte - myByte = 5 |
| DSCODE.NULL.toByte()}; |
| |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| System.out.println("\n"); |
| |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| SimpleClass actualVal = (SimpleClass) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + object + " Value Read..." + actualVal, |
| object.equals(actualVal)); |
| |
| } |
| |
| @Test |
| public void testByteFormatForStrings() throws Exception { |
| boolean myFlag = true; |
| short myShort = 25; |
| String myString1 = "Class4_myString1"; |
| long myLong = 15654; |
| String myString2 = "Class4_myString2"; |
| String myString3 = "Class4_myString3"; |
| int myInt = 1420; |
| float myFloat = 123.023f; |
| |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| SimpleClass1 pdx = |
| new SimpleClass1(myFlag, myShort, myString1, myLong, myString2, myString3, myInt, myFloat); |
| DataSerializer.writeObject(pdx, out); |
| int typeId = getPdxTypeIdForClass(SimpleClass1.class); |
| |
| HeapDataOutputStream hdos1 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString1, hdos1); |
| byte[] str1Bytes = hdos1.toByteArray(); |
| HeapDataOutputStream hdos2 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString2, hdos2); |
| byte[] str2Bytes = hdos2.toByteArray(); |
| HeapDataOutputStream hdos3 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString3, hdos3); |
| byte[] str3Bytes = hdos3.toByteArray(); |
| |
| int length = 1 /* myFlag */ + 2 /* myShort */ |
| + 8 /* myLong */ + 4 /* myInt */ + 4 /* myFloat */ + str1Bytes.length + str2Bytes.length |
| + str3Bytes.length + 2 /* byte offset for 3 strings */; |
| |
| int offset1 = 1 + 2; |
| int offset2 = offset1 + 8 + str1Bytes.length; |
| int offset3 = offset1 + 8 + str1Bytes.length + str2Bytes.length; |
| byte[] actual = out.toByteArray(); |
| int floatBytes = Float.floatToRawIntBits(myFloat); |
| Byte[] expected = new Byte[] {DSCODE.PDX.toByte(), // byte |
| (byte) (length >> 24), (byte) (length >> 16), (byte) (length >> 8), (byte) length, // int - |
| // length |
| // of |
| // byte |
| // stream |
| (byte) (typeId >> 24), (byte) (typeId >> 16), (byte) (typeId >> 8), (byte) typeId, // int - |
| // typeId |
| 1, // boolean - myFlag = true |
| (byte) (myShort >> 8), (byte) myShort, // short - myShort |
| (byte) (myLong >> 56), (byte) (myLong >> 48), (byte) (myLong >> 40), (byte) (myLong >> 32), |
| (byte) (myLong >> 24), (byte) (myLong >> 16), (byte) (myLong >> 8), (byte) myLong, // long - |
| // myLong |
| (byte) (myInt >> 24), (byte) (myInt >> 16), (byte) (myInt >> 8), (byte) myInt, // int - |
| // myInt |
| (byte) (floatBytes >> 24), (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), |
| (byte) floatBytes, // float - myFloat |
| (byte) offset3, // offset of myString3 |
| (byte) offset2, // offset of myString2 |
| }; |
| |
| for (int i = (str1Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset1 + PdxWriterImpl.HEADER_SIZE, str1Bytes[i]); // + |
| // 5 |
| // for: |
| // 1 |
| // for |
| // DSCODE.PDX.toByte() |
| // and |
| // 4 |
| // for |
| // byte |
| // stream |
| // length |
| } |
| for (int i = (str2Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset2 + PdxWriterImpl.HEADER_SIZE, str2Bytes[i]); |
| } |
| for (int i = (str3Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset3 + PdxWriterImpl.HEADER_SIZE, str3Bytes[i]); |
| } |
| |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| if (actual.length != expected.length) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| System.out.println("\n"); |
| |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| SimpleClass1 actualVal = (SimpleClass1) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| |
| cache.setReadSerializedForTest(true); |
| try { |
| in = new DataInputStream(new ByteArrayInputStream(actual)); |
| PdxInstance pi = (PdxInstance) DataSerializer.readObject(in); |
| actualVal = (SimpleClass1) pi.getObject(); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| assertTrue(pi.hasField("myFlag")); |
| assertTrue(pi.hasField("myShort")); |
| assertTrue(pi.hasField("myString1")); |
| assertTrue(pi.hasField("myLong")); |
| assertTrue(pi.hasField("myString2")); |
| assertTrue(pi.hasField("myString3")); |
| assertTrue(pi.hasField("myInt")); |
| assertTrue(pi.hasField("myFloat")); |
| assertEquals(pdx.isMyFlag(), pi.getField("myFlag")); |
| assertEquals(pdx.getMyShort(), pi.getField("myShort")); |
| assertEquals(pdx.getMyString1(), pi.getField("myString1")); |
| assertEquals(pdx.getMyLong(), pi.getField("myLong")); |
| assertEquals(pdx.getMyString2(), pi.getField("myString2")); |
| assertEquals(pdx.getMyString3(), pi.getField("myString3")); |
| assertEquals(pdx.getMyInt(), pi.getField("myInt")); |
| assertEquals(pdx.getMyFloat(), pi.getField("myFloat")); |
| PdxReaderImpl reader = (PdxReaderImpl) pi; |
| PdxType type = reader.getPdxType(); |
| assertEquals(SimpleClass1.class.getName(), type.getClassName()); |
| assertEquals(8, type.getFieldCount()); |
| assertEquals(2, type.getVariableLengthFieldCount()); |
| |
| assertEquals(0, type.getPdxField("myFlag").getFieldIndex()); |
| assertEquals(1, type.getPdxField("myShort").getFieldIndex()); |
| assertEquals(2, type.getPdxField("myString1").getFieldIndex()); |
| assertEquals(3, type.getPdxField("myLong").getFieldIndex()); |
| assertEquals(4, type.getPdxField("myString2").getFieldIndex()); |
| assertEquals(5, type.getPdxField("myString3").getFieldIndex()); |
| assertEquals(6, type.getPdxField("myInt").getFieldIndex()); |
| assertEquals(7, type.getPdxField("myFloat").getFieldIndex()); |
| |
| assertEquals(FieldType.BOOLEAN, type.getPdxField("myFlag").getFieldType()); |
| assertEquals(FieldType.SHORT, type.getPdxField("myShort").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString1").getFieldType()); |
| assertEquals(FieldType.LONG, type.getPdxField("myLong").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString2").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString3").getFieldType()); |
| assertEquals(FieldType.INT, type.getPdxField("myInt").getFieldType()); |
| assertEquals(FieldType.FLOAT, type.getPdxField("myFloat").getFieldType()); |
| |
| assertEquals("myFlag", type.getPdxField("myFlag").getFieldName()); |
| assertEquals("myShort", type.getPdxField("myShort").getFieldName()); |
| assertEquals("myString1", type.getPdxField("myString1").getFieldName()); |
| assertEquals("myLong", type.getPdxField("myLong").getFieldName()); |
| assertEquals("myString2", type.getPdxField("myString2").getFieldName()); |
| assertEquals("myString3", type.getPdxField("myString3").getFieldName()); |
| assertEquals("myInt", type.getPdxField("myInt").getFieldName()); |
| assertEquals("myFloat", type.getPdxField("myFloat").getFieldName()); |
| |
| assertEquals(0, type.getPdxField("myFlag").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myShort").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myString1").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myLong").getVarLenFieldSeqId()); |
| assertEquals(1, type.getPdxField("myString2").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myString3").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myInt").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myFloat").getVarLenFieldSeqId()); |
| |
| assertEquals(false, type.getPdxField("myFlag").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myShort").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString1").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myLong").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString2").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString3").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myInt").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myFloat").isVariableLengthType()); |
| |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (pdx.isMyFlag() ? 1 : 0)}), |
| reader.getRaw(0)); |
| assertEquals( |
| ByteSourceFactory |
| .wrap(new byte[] {(byte) (pdx.getMyShort() >> 8), (byte) pdx.getMyShort()}), |
| reader.getRaw(1)); |
| assertEquals(ByteSourceFactory.wrap(str1Bytes), reader.getRaw(2)); |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (pdx.getMyLong() >> 56), |
| (byte) (pdx.getMyLong() >> 48), (byte) (pdx.getMyLong() >> 40), |
| (byte) (pdx.getMyLong() >> 32), (byte) (pdx.getMyLong() >> 24), |
| (byte) (pdx.getMyLong() >> 16), (byte) (pdx.getMyLong() >> 8), (byte) pdx.getMyLong(),}), |
| reader.getRaw(3)); |
| assertEquals(ByteSourceFactory.wrap(str2Bytes), reader.getRaw(4)); |
| assertEquals(ByteSourceFactory.wrap(str3Bytes), reader.getRaw(5)); |
| assertEquals( |
| ByteSourceFactory.wrap(new byte[] {(byte) (pdx.getMyInt() >> 24), |
| (byte) (pdx.getMyInt() >> 16), (byte) (pdx.getMyInt() >> 8), (byte) pdx.getMyInt()}), |
| reader.getRaw(6)); |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (floatBytes >> 24), |
| (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), (byte) floatBytes}), |
| reader.getRaw(7)); |
| } finally { |
| cache.setReadSerializedForTest(false); |
| } |
| } |
| |
| |
| @Test |
| public void testByteFormatForLongStrings() throws Exception { |
| boolean myFlag = true; |
| short myShort = 25; |
| String myString1 = |
| "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1." |
| + "A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1.A very long string1."; |
| long myLong = 15654; |
| String myString2 = "Class4_myString2"; |
| String myString3 = |
| "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. " |
| + "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. " |
| + "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. " |
| + "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. " |
| + "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. " |
| + "Even longer string3. Even longer string3. Even longer string3. Even longer string3. Even longer string3. "; |
| int myInt = 1420; |
| float myFloat = 123.023f; |
| |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| SimpleClass1 pdx = |
| new SimpleClass1(myFlag, myShort, myString1, myLong, myString2, myString3, myInt, myFloat); |
| DataSerializer.writeObject(pdx, out); |
| int typeId = getPdxTypeIdForClass(SimpleClass1.class); |
| |
| HeapDataOutputStream hdos1 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString1, hdos1); |
| byte[] str1Bytes = hdos1.toByteArray(); |
| HeapDataOutputStream hdos2 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString2, hdos2); |
| byte[] str2Bytes = hdos2.toByteArray(); |
| HeapDataOutputStream hdos3 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString3, hdos3); |
| byte[] str3Bytes = hdos3.toByteArray(); |
| |
| int length = 1 /* myFlag */ + 2 /* myShort */ |
| + 8 /* myLong */ + 4 /* myInt */ + 4 /* myFloat */ + str1Bytes.length + str2Bytes.length |
| + str3Bytes.length + (2 * 2) /* short offset for 3 strings */; |
| |
| int offset1 = 1 + 2; |
| int offset2 = offset1 + 8 + str1Bytes.length; |
| int offset3 = offset1 + 8 + str1Bytes.length + str2Bytes.length; |
| byte[] actual = out.toByteArray(); |
| int floatBytes = Float.floatToRawIntBits(myFloat); |
| Byte[] expected = new Byte[] {DSCODE.PDX.toByte(), // byte |
| (byte) (length >> 24), (byte) (length >> 16), (byte) (length >> 8), (byte) length, // int - |
| // length |
| // of |
| // byte |
| // stream |
| (byte) (typeId >> 24), (byte) (typeId >> 16), (byte) (typeId >> 8), (byte) typeId, // int - |
| // typeId |
| 1, // boolean - myFlag = true |
| (byte) (myShort >> 8), (byte) myShort, // short - myShort |
| (byte) (myLong >> 56), (byte) (myLong >> 48), (byte) (myLong >> 40), (byte) (myLong >> 32), |
| (byte) (myLong >> 24), (byte) (myLong >> 16), (byte) (myLong >> 8), (byte) myLong, // long - |
| // myLong |
| (byte) (myInt >> 24), (byte) (myInt >> 16), (byte) (myInt >> 8), (byte) myInt, // int - |
| // myInt |
| (byte) (floatBytes >> 24), (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), |
| (byte) floatBytes, // float - myFloat |
| (byte) (offset3 >> 8), (byte) offset3, // offset of myString3 |
| (byte) (offset2 >> 8), (byte) offset2, // offset of myString2 |
| }; |
| |
| for (int i = (str1Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset1 + PdxWriterImpl.HEADER_SIZE, str1Bytes[i]); // + |
| // 5 |
| // for: |
| // 1 |
| // for |
| // DSCODE.PDX.toByte() |
| // and |
| // 4 |
| // for |
| // byte |
| // stream |
| // length |
| } |
| for (int i = (str2Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset2 + PdxWriterImpl.HEADER_SIZE, str2Bytes[i]); |
| } |
| for (int i = (str3Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset3 + PdxWriterImpl.HEADER_SIZE, str3Bytes[i]); |
| } |
| |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| if (actual.length != expected.length) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| System.out.println("\n"); |
| |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| SimpleClass1 actualVal = (SimpleClass1) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| cache.setReadSerializedForTest(true); |
| try { |
| in = new DataInputStream(new ByteArrayInputStream(actual)); |
| PdxInstance pi = (PdxInstance) DataSerializer.readObject(in); |
| actualVal = (SimpleClass1) pi.getObject(); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| assertTrue(pi.hasField("myFlag")); |
| assertTrue(pi.hasField("myShort")); |
| assertTrue(pi.hasField("myString1")); |
| assertTrue(pi.hasField("myLong")); |
| assertTrue(pi.hasField("myString2")); |
| assertTrue(pi.hasField("myString3")); |
| assertTrue(pi.hasField("myInt")); |
| assertTrue(pi.hasField("myFloat")); |
| assertEquals(pdx.isMyFlag(), pi.getField("myFlag")); |
| assertEquals(pdx.getMyShort(), pi.getField("myShort")); |
| assertEquals(pdx.getMyString1(), pi.getField("myString1")); |
| assertEquals(pdx.getMyLong(), pi.getField("myLong")); |
| assertEquals(pdx.getMyString2(), pi.getField("myString2")); |
| assertEquals(pdx.getMyString3(), pi.getField("myString3")); |
| assertEquals(pdx.getMyInt(), pi.getField("myInt")); |
| assertEquals(pdx.getMyFloat(), pi.getField("myFloat")); |
| PdxReaderImpl reader = (PdxReaderImpl) pi; |
| PdxType type = reader.getPdxType(); |
| assertEquals(SimpleClass1.class.getName(), type.getClassName()); |
| assertEquals(8, type.getFieldCount()); |
| assertEquals(2, type.getVariableLengthFieldCount()); |
| |
| assertEquals(0, type.getPdxField("myFlag").getFieldIndex()); |
| assertEquals(1, type.getPdxField("myShort").getFieldIndex()); |
| assertEquals(2, type.getPdxField("myString1").getFieldIndex()); |
| assertEquals(3, type.getPdxField("myLong").getFieldIndex()); |
| assertEquals(4, type.getPdxField("myString2").getFieldIndex()); |
| assertEquals(5, type.getPdxField("myString3").getFieldIndex()); |
| assertEquals(6, type.getPdxField("myInt").getFieldIndex()); |
| assertEquals(7, type.getPdxField("myFloat").getFieldIndex()); |
| |
| assertEquals(FieldType.BOOLEAN, type.getPdxField("myFlag").getFieldType()); |
| assertEquals(FieldType.SHORT, type.getPdxField("myShort").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString1").getFieldType()); |
| assertEquals(FieldType.LONG, type.getPdxField("myLong").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString2").getFieldType()); |
| assertEquals(FieldType.STRING, type.getPdxField("myString3").getFieldType()); |
| assertEquals(FieldType.INT, type.getPdxField("myInt").getFieldType()); |
| assertEquals(FieldType.FLOAT, type.getPdxField("myFloat").getFieldType()); |
| |
| assertEquals("myFlag", type.getPdxField("myFlag").getFieldName()); |
| assertEquals("myShort", type.getPdxField("myShort").getFieldName()); |
| assertEquals("myString1", type.getPdxField("myString1").getFieldName()); |
| assertEquals("myLong", type.getPdxField("myLong").getFieldName()); |
| assertEquals("myString2", type.getPdxField("myString2").getFieldName()); |
| assertEquals("myString3", type.getPdxField("myString3").getFieldName()); |
| assertEquals("myInt", type.getPdxField("myInt").getFieldName()); |
| assertEquals("myFloat", type.getPdxField("myFloat").getFieldName()); |
| |
| assertEquals(0, type.getPdxField("myFlag").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myShort").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myString1").getVarLenFieldSeqId()); |
| assertEquals(0, type.getPdxField("myLong").getVarLenFieldSeqId()); |
| assertEquals(1, type.getPdxField("myString2").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myString3").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myInt").getVarLenFieldSeqId()); |
| assertEquals(2, type.getPdxField("myFloat").getVarLenFieldSeqId()); |
| |
| assertEquals(false, type.getPdxField("myFlag").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myShort").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString1").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myLong").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString2").isVariableLengthType()); |
| assertEquals(true, type.getPdxField("myString3").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myInt").isVariableLengthType()); |
| assertEquals(false, type.getPdxField("myFloat").isVariableLengthType()); |
| |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (pdx.isMyFlag() ? 1 : 0)}), |
| reader.getRaw(0)); |
| assertEquals( |
| ByteSourceFactory |
| .wrap(new byte[] {(byte) (pdx.getMyShort() >> 8), (byte) pdx.getMyShort()}), |
| reader.getRaw(1)); |
| assertEquals(ByteSourceFactory.wrap(str1Bytes), reader.getRaw(2)); |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (pdx.getMyLong() >> 56), |
| (byte) (pdx.getMyLong() >> 48), (byte) (pdx.getMyLong() >> 40), |
| (byte) (pdx.getMyLong() >> 32), (byte) (pdx.getMyLong() >> 24), |
| (byte) (pdx.getMyLong() >> 16), (byte) (pdx.getMyLong() >> 8), (byte) pdx.getMyLong(),}), |
| reader.getRaw(3)); |
| assertEquals(ByteSourceFactory.wrap(str2Bytes), reader.getRaw(4)); |
| assertEquals(ByteSourceFactory.wrap(str3Bytes), reader.getRaw(5)); |
| assertEquals( |
| ByteSourceFactory.wrap(new byte[] {(byte) (pdx.getMyInt() >> 24), |
| (byte) (pdx.getMyInt() >> 16), (byte) (pdx.getMyInt() >> 8), (byte) pdx.getMyInt()}), |
| reader.getRaw(6)); |
| assertEquals(ByteSourceFactory.wrap(new byte[] {(byte) (floatBytes >> 24), |
| (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), (byte) floatBytes}), |
| reader.getRaw(7)); |
| } finally { |
| cache.setReadSerializedForTest(false); |
| } |
| } |
| |
| |
| @Test |
| public void testByteFormatForNestedPDX() throws Exception { |
| String myString1 = "ComplexClass1_myString1"; |
| long myLong = 15654; |
| HashMap<String, PdxSerializable> myHashMap = new HashMap<String, PdxSerializable>(); |
| String myString2 = "ComplexClass1_myString2"; |
| float myFloat = 123.023f; |
| |
| for (int i = 0; i < 5; i++) { |
| myHashMap.put("KEY_" + i, new SimpleClass(i, (byte) 5)); |
| } |
| |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| PdxSerializable pdx = new NestedPdx(myString1, myLong, myHashMap, myString2, myFloat); |
| DataSerializer.writeObject(pdx, out); |
| int typeId = getPdxTypeIdForClass(NestedPdx.class); |
| |
| HeapDataOutputStream hdos1 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString1, hdos1); |
| byte[] str1Bytes = hdos1.toByteArray(); |
| HeapDataOutputStream hdosForMap = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(myHashMap, hdosForMap); |
| byte[] mapBytes = hdosForMap.toByteArray(); |
| HeapDataOutputStream hdos2 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString2, hdos2); |
| byte[] str2Bytes = hdos2.toByteArray(); |
| |
| int length = str1Bytes.length + 8 /* myLong */ |
| + mapBytes.length + str2Bytes.length + 4 /* myFloat */ |
| + (2 * 1) /* |
| * offset for 3 var-length fields |
| */; |
| |
| int offset1 = 0; |
| int offset2 = offset1 + 8 + str1Bytes.length; |
| int offset3 = offset1 + 8 + str1Bytes.length + mapBytes.length; |
| byte[] actual = out.toByteArray(); |
| int floatBytes = Float.floatToRawIntBits(myFloat); |
| Byte[] expected = new Byte[] {DSCODE.PDX.toByte(), // byte |
| (byte) (length >> 24), (byte) (length >> 16), (byte) (length >> 8), (byte) length, // int - |
| // length |
| // of |
| // byte |
| // stream |
| (byte) (typeId >> 24), (byte) (typeId >> 16), (byte) (typeId >> 8), (byte) typeId, // int - |
| // typeId |
| (byte) (myLong >> 56), (byte) (myLong >> 48), (byte) (myLong >> 40), (byte) (myLong >> 32), |
| (byte) (myLong >> 24), (byte) (myLong >> 16), (byte) (myLong >> 8), (byte) myLong, // long - |
| // myLong |
| (byte) (floatBytes >> 24), (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), |
| (byte) floatBytes, // float - myFloat |
| (byte) offset3, // offset of myString2 |
| (byte) offset2, // offset of myHashMap |
| }; |
| |
| for (int i = (str1Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset1 + PdxWriterImpl.HEADER_SIZE, str1Bytes[i]); |
| } |
| for (int i = (mapBytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset2 + PdxWriterImpl.HEADER_SIZE, mapBytes[i]); |
| } |
| for (int i = (str2Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset3 + PdxWriterImpl.HEADER_SIZE, str2Bytes[i]); |
| } |
| |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| if (actual.length != expected.length) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| System.out.println("\n"); |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| NestedPdx actualVal = (NestedPdx) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| System.out.println("\n"); |
| } |
| |
| @Test |
| public void testByteFormatForDSInsidePDX() throws Exception { |
| String myString1 = "ComplexClass1_myString1"; |
| long myLong = 15654; |
| DataSerializable myDS = new DeltaTestImpl(100, "value"); |
| String myString2 = "ComplexClass1_myString2"; |
| float myFloat = 123.023f; |
| |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| PdxSerializable pdx = new DSInsidePdx(myString1, myLong, myDS, myString2, myFloat); |
| DataSerializer.writeObject(pdx, out); |
| int typeId = getPdxTypeIdForClass(DSInsidePdx.class); |
| |
| HeapDataOutputStream hdos1 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString1, hdos1); |
| byte[] str1Bytes = hdos1.toByteArray(); |
| System.out.println("Length of string1: " + str1Bytes.length); |
| |
| HeapDataOutputStream hdos2 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(myDS, hdos2); |
| byte[] dsBytes = hdos2.toByteArray(); |
| System.out.println("Length of DS: " + dsBytes.length); |
| |
| HeapDataOutputStream hdos3 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString2, hdos3); |
| byte[] str2Bytes = hdos3.toByteArray(); |
| System.out.println("Length of string2: " + str2Bytes.length); |
| |
| int length = str1Bytes.length + 8 /* myLong */ |
| + dsBytes.length + str2Bytes.length + 4 /* myFloat */ |
| + (2 * 2) /* |
| * offset for 3 car-length fields |
| */; |
| |
| int offset1 = 0; |
| int offset2 = offset1 + 8 + str1Bytes.length; |
| int offset3 = offset1 + 8 + str1Bytes.length + dsBytes.length; |
| byte[] actual = out.toByteArray(); |
| int floatBytes = Float.floatToRawIntBits(myFloat); |
| Byte[] expected = new Byte[] {DSCODE.PDX.toByte(), // byte |
| (byte) (length >> 24), (byte) (length >> 16), (byte) (length >> 8), (byte) length, // int - |
| // length |
| // of |
| // byte |
| // stream |
| (byte) (typeId >> 24), (byte) (typeId >> 16), (byte) (typeId >> 8), (byte) typeId, // int - |
| // typeId |
| (byte) (myLong >> 56), (byte) (myLong >> 48), (byte) (myLong >> 40), (byte) (myLong >> 32), |
| (byte) (myLong >> 24), (byte) (myLong >> 16), (byte) (myLong >> 8), (byte) myLong, // long - |
| // myLong |
| (byte) (floatBytes >> 24), (byte) (floatBytes >> 16), (byte) (floatBytes >> 8), |
| (byte) floatBytes, // float - myFloat |
| (byte) (offset3 >> 8), (byte) offset3, // offset of myString2 |
| (byte) (offset2 >> 8), (byte) offset2, // offset of myHashMap |
| }; |
| |
| for (int i = (str1Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset1 + PdxWriterImpl.HEADER_SIZE, str1Bytes[i]); // + |
| // 5 |
| // for: |
| // 1 |
| // for |
| // DSCODE.PDX.toByte() |
| // and |
| // 4 |
| // for |
| // byte |
| // stream |
| // length |
| } |
| for (int i = (dsBytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset2 + PdxWriterImpl.HEADER_SIZE, dsBytes[i]); |
| } |
| for (int i = (str2Bytes.length - 1); i >= 0; i--) { |
| expected = |
| (Byte[]) ArrayUtils.insert(expected, offset3 + PdxWriterImpl.HEADER_SIZE, str2Bytes[i]); |
| } |
| |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| System.out.println("\n"); |
| |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| DSInsidePdx actualVal = (DSInsidePdx) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + pdx + " Value Read..." + actualVal, |
| pdx.equals(actualVal)); |
| System.out.println("\n"); |
| } |
| |
| @Test |
| public void testByteFormatForPDXInsideDS() throws Exception { |
| String myString1 = "ComplexClass5_myString1"; |
| long myLong = 15654; |
| String myString2 = "ComplexClass5_myString2"; |
| float myFloat = 123.023f; |
| |
| HashMap<String, PdxSerializable> myHashMap = new HashMap<String, PdxSerializable>(); |
| for (int i = 0; i < 2; i++) { |
| myHashMap.put("KEY_" + i, new SimpleClass(i, (byte) i)); |
| } |
| PdxSerializable myPDX = new NestedPdx(myString1, myLong, myHashMap, myString2, myFloat); |
| |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializable ds = new PdxInsideDS(myString1, myLong, myPDX, myString2); |
| DataSerializer.writeObject(ds, out); |
| |
| HeapDataOutputStream hdosString1 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString1, hdosString1); |
| byte[] str1Bytes = hdosString1.toByteArray(); |
| System.out.println("Length of string1: " + str1Bytes.length); |
| |
| HeapDataOutputStream hdosMyPDX = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(myPDX, hdosMyPDX); |
| byte[] pdxBytes = hdosMyPDX.toByteArray(); |
| System.out.println("Length of myPDX: " + pdxBytes.length); |
| |
| HeapDataOutputStream hdosString2 = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeString(myString2, hdosString2); |
| byte[] str2Bytes = hdosString2.toByteArray(); |
| System.out.println("Length of string2: " + str2Bytes.length); |
| |
| Class classInstance = ds.getClass(); |
| HeapDataOutputStream hdosClass = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeClass(classInstance, hdosClass); |
| byte[] dsInitBytes = hdosClass.toByteArray(); |
| |
| int offsetStr1 = 1 + dsInitBytes.length; |
| int offsetPDX = 1 + dsInitBytes.length + str1Bytes.length + 8; |
| int offsetStr2 = 1 + dsInitBytes.length + str1Bytes.length + 8 + pdxBytes.length; |
| |
| byte[] actual = out.toByteArray(); |
| int floatBytes = Float.floatToRawIntBits(myFloat); |
| Byte[] expected = new Byte[] {DSCODE.DATA_SERIALIZABLE.toByte(), // byte |
| (byte) (myLong >> 56), (byte) (myLong >> 48), (byte) (myLong >> 40), (byte) (myLong >> 32), |
| (byte) (myLong >> 24), (byte) (myLong >> 16), (byte) (myLong >> 8), (byte) myLong, // long - |
| // myLong |
| }; |
| |
| for (int i = (dsInitBytes.length - 1); i >= 0; i--) { |
| expected = (Byte[]) ArrayUtils.insert(expected, 1, dsInitBytes[i]); |
| } |
| for (int i = (str1Bytes.length - 1); i >= 0; i--) { |
| expected = (Byte[]) ArrayUtils.insert(expected, offsetStr1, str1Bytes[i]); |
| } |
| for (int i = (pdxBytes.length - 1); i >= 0; i--) { |
| expected = (Byte[]) ArrayUtils.insert(expected, offsetPDX, pdxBytes[i]); |
| } |
| for (int i = (str2Bytes.length - 1); i >= 0; i--) { |
| expected = (Byte[]) ArrayUtils.insert(expected, offsetStr2, str2Bytes[i]); |
| } |
| |
| checkBytes(expected, actual); |
| |
| DataInput in = new DataInputStream(new ByteArrayInputStream(actual)); |
| PdxInsideDS actualVal = (PdxInsideDS) DataSerializer.readObject(in); |
| // System.out.println("actualVal..."+actualVal); |
| assertTrue( |
| "Mismatch in write and read value: Value Write..." + ds + " Value Read..." + actualVal, |
| ds.equals(actualVal)); |
| } |
| |
| private void checkBytes(Byte[] expected, byte[] actual) { |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| if (actual.length != expected.length) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| } |
| |
| private void checkBytes(byte[] expected, byte[] actual) { |
| StringBuffer msg = new StringBuffer("Actual output: "); |
| for (byte val : actual) { |
| msg.append(val + ", "); |
| } |
| msg.append("\nExpected output: "); |
| for (byte val : expected) { |
| msg.append(val + ", "); |
| } |
| if (actual.length != expected.length) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch in length, actual.length: " + actual.length + " and expected length: " |
| + expected.length, actual.length == expected.length); |
| for (int i = 0; i < actual.length; i++) { |
| if (actual[i] != expected[i]) { |
| System.out.println(msg.toString()); |
| } |
| assertTrue("Mismatch at index " + i, actual[i] == expected[i]); |
| } |
| } |
| |
| @Test |
| public void testLong() throws IOException, ClassNotFoundException { |
| LongHolder v = (LongHolder) serializeAndDeserialize(new LongHolder(0x69)); |
| assertEquals(0x69, v.getLong()); |
| } |
| |
| // this method adds coverage for bug 43236 |
| @Test |
| public void testObjectPdxInstance() throws IOException, ClassNotFoundException { |
| Boolean previousPdxReadSerializedFlag = cache.getPdxReadSerializedOverride(); |
| cache.setPdxReadSerializedOverride(true); |
| PdxReaderImpl.TESTHOOK_TRACKREADS = true; |
| try { |
| PdxInstance pi = (PdxInstance) serializeAndDeserialize(new ObjectHolder("hello")); |
| ObjectHolder v3 = (ObjectHolder) pi.getObject(); |
| WritablePdxInstance wpi = pi.createWriter(); |
| wpi.setField("f1", "goodbye"); |
| assertEquals("goodbye", wpi.getField("f1")); |
| ObjectHolder v = (ObjectHolder) wpi.getObject(); |
| ObjectHolder v2 = (ObjectHolder) wpi.getObject(); |
| assertEquals("goodbye", v.getObject()); |
| assertEquals("goodbye", v2.getObject()); |
| assertEquals("hello", v3.getObject()); |
| assertEquals("goodbye", wpi.getField("f1")); |
| } finally { |
| cache.setPdxReadSerializedOverride(previousPdxReadSerializedFlag); |
| PdxReaderImpl.TESTHOOK_TRACKREADS = false; |
| } |
| } |
| |
| @Test |
| public void testObjectArrayPdxInstance() throws IOException, ClassNotFoundException { |
| Boolean previousPdxReadSerializedFlag = cache.getPdxReadSerializedOverride(); |
| cache.setPdxReadSerializedOverride(true); |
| PdxReaderImpl.TESTHOOK_TRACKREADS = true; |
| try { |
| LongFieldHolder[] v = new LongFieldHolder[] {new LongFieldHolder(1), new LongFieldHolder(2)}; |
| PdxInstance pi = (PdxInstance) serializeAndDeserialize(new ObjectArrayHolder(v)); |
| ObjectArrayHolder oah = (ObjectArrayHolder) pi.getObject(); |
| LongFieldHolder[] nv = (LongFieldHolder[]) oah.getObjectArray(); |
| if (!Arrays.equals(v, nv)) { |
| throw new RuntimeException( |
| "expected " + Arrays.toString(v) + " but had " + Arrays.toString(nv)); |
| } |
| Object[] oa = (Object[]) pi.getField("f1"); |
| assertTrue(oa[0] instanceof PdxInstance); |
| assertTrue(oa[1] instanceof PdxInstance); |
| LongFieldHolder[] nv2 = new LongFieldHolder[2]; |
| nv2[0] = (LongFieldHolder) ((PdxInstance) oa[0]).getObject(); |
| nv2[1] = (LongFieldHolder) ((PdxInstance) oa[1]).getObject(); |
| if (!Arrays.equals(v, nv2)) { |
| throw new RuntimeException( |
| "expected " + Arrays.toString(v) + " but had " + Arrays.toString(nv2)); |
| } |
| } finally { |
| cache.setPdxReadSerializedOverride(previousPdxReadSerializedFlag); |
| PdxReaderImpl.TESTHOOK_TRACKREADS = false; |
| } |
| } |
| |
| @Test |
| public void testLongField() throws IOException, ClassNotFoundException { |
| LongFieldHolder v = |
| (LongFieldHolder) serializeAndDeserialize(new LongFieldHolder(0x1020304050607080L)); |
| assertEquals(0x1020304050607080L, v.getLong()); |
| } |
| |
| @Test |
| public void testAll() throws IOException, ClassNotFoundException { |
| AllFieldTypes v1 = new AllFieldTypes(0x1020304050607080L, false); |
| AllFieldTypes v2 = (AllFieldTypes) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| @Test |
| public void testBasicAll() throws IOException, ClassNotFoundException { |
| BasicAllFieldTypes v1 = new BasicAllFieldTypes(0x1020304050607080L, false); |
| try { |
| serializeAndDeserialize(v1); |
| throw new RuntimeException("expected NotSerializableException"); |
| } catch (NotSerializableException expected) { |
| |
| } |
| this.cache.setPdxSerializer(new BasicAllFieldTypesPdxSerializer()); |
| try { |
| BasicAllFieldTypes v2 = (BasicAllFieldTypes) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } finally { |
| this.cache.setPdxSerializer(null); |
| } |
| } |
| |
| @Test |
| public void testPdxSerializerFalse() throws IOException, ClassNotFoundException { |
| this.cache.setPdxSerializer(new BasicAllFieldTypesPdxSerializer()); |
| try { |
| POS v1 = new POS(3); |
| POS v2 = (POS) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } finally { |
| this.cache.setPdxSerializer(null); |
| } |
| } |
| |
| @Test |
| public void testAllWithNulls() throws IOException, ClassNotFoundException { |
| AllFieldTypes v1 = new AllFieldTypes(0x102030405060708L, true); |
| AllFieldTypes v2 = (AllFieldTypes) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| @Test |
| public void testBasicAllWithNulls() throws IOException, ClassNotFoundException { |
| BasicAllFieldTypes v1 = new BasicAllFieldTypes(0x1020304050607080L, true); |
| try { |
| serializeAndDeserialize(v1); |
| throw new RuntimeException("expected NotSerializableException"); |
| } catch (NotSerializableException expected) { |
| |
| } |
| this.cache.setPdxSerializer(new BasicAllFieldTypesPdxSerializer()); |
| try { |
| BasicAllFieldTypes v2 = (BasicAllFieldTypes) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } finally { |
| this.cache.setPdxSerializer(null); |
| } |
| } |
| |
| @Test |
| public void testAllRF() throws IOException, ClassNotFoundException { |
| AllFieldTypesRF v1 = new AllFieldTypesRF(0x1020304050607080L, false); |
| AllFieldTypesRF v2 = (AllFieldTypesRF) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| @Test |
| public void testAllWithNullsRF() throws IOException, ClassNotFoundException { |
| AllFieldTypesRF v1 = new AllFieldTypesRF(0x102030405060708L, true); |
| AllFieldTypesRF v2 = (AllFieldTypesRF) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| @Test |
| public void testAllWF() throws IOException, ClassNotFoundException { |
| AllFieldTypesWF v1 = new AllFieldTypesWF(0x1020304050607080L, false); |
| AllFieldTypesWF v2 = (AllFieldTypesWF) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| @Test |
| public void testAllWithNullsWF() throws IOException, ClassNotFoundException { |
| AllFieldTypesWF v1 = new AllFieldTypesWF(0x102030405060708L, true); |
| AllFieldTypesWF v2 = (AllFieldTypesWF) serializeAndDeserialize(v1); |
| assertEquals(v1, v2); |
| } |
| |
| private Object serializeAndDeserialize(Object in) throws IOException, ClassNotFoundException { |
| HeapDataOutputStream hdos = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(in, hdos); |
| byte[] bytes = hdos.toByteArray(); |
| System.out.println("Serialized bytes = " + Arrays.toString(bytes)); |
| return DataSerializer.readObject(new DataInputStream(new ByteArrayInputStream(bytes))); |
| } |
| |
| public static class LongHolder implements PdxSerializable { |
| private long v; |
| |
| public LongHolder(long v) { |
| this.v = v; |
| } |
| |
| public LongHolder() { |
| |
| } |
| |
| public long getLong() { |
| return this.v; |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| writer.writeLong("f1", this.v); |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| this.v = reader.readLong("f1"); |
| } |
| } |
| public static class ObjectHolder implements PdxSerializable { |
| private Object v; |
| |
| public ObjectHolder(Object v) { |
| this.v = v; |
| } |
| |
| public ObjectHolder() { |
| |
| } |
| |
| public Object getObject() { |
| return this.v; |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| writer.writeObject("f1", this.v); |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| this.v = reader.readObject("f1"); |
| } |
| } |
| public static class ObjectArrayHolder implements PdxSerializable { |
| private Object[] v; |
| |
| public ObjectArrayHolder(Object[] v) { |
| this.v = v; |
| } |
| |
| public ObjectArrayHolder() { |
| |
| } |
| |
| public Object[] getObjectArray() { |
| return this.v; |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| writer.writeObjectArray("f1", this.v); |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| this.v = reader.readObjectArray("f1"); |
| } |
| } |
| |
| public static class LongFieldHolder implements PdxSerializable { |
| private long v; |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + (int) (v ^ (v >>> 32)); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| LongFieldHolder other = (LongFieldHolder) obj; |
| if (v != other.v) |
| return false; |
| return true; |
| } |
| |
| public LongFieldHolder(long v) { |
| this.v = v; |
| } |
| |
| public LongFieldHolder() { |
| |
| } |
| |
| public long getLong() { |
| return this.v; |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| writer.writeLong("f1", this.v); |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| this.v = (Long) reader.readField("f1"); |
| } |
| } |
| |
| public enum Day { |
| SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY |
| } |
| |
| public static class BasicAllFieldTypes implements PdxSerializerObject { |
| |
| public static String FILE_NAME = "testFile.txt"; |
| |
| // additional fields from tests.util.ValueHolder |
| public char aChar; |
| public boolean aBoolean; |
| public byte aByte; |
| public short aShort; |
| public int anInt; |
| public long aLong; |
| public float aFloat; |
| public double aDouble; |
| public Date aDate; |
| public String aString; |
| public Object anObject; |
| public Map aMap; |
| public Collection aCollection; |
| public boolean[] aBooleanArray; |
| public char[] aCharArray; |
| public byte[] aByteArray; |
| public short[] aShortArray; |
| public int[] anIntArray; |
| public long[] aLongArray; |
| public float[] aFloatArray; |
| public double[] aDoubleArray; |
| public String[] aStringArray; |
| public Object[] anObjectArray; |
| public byte[][] anArrayOfByteArray; |
| |
| public BasicAllFieldTypes() {} |
| |
| public BasicAllFieldTypes(long base, boolean nulls) { |
| fillInBaseValues(base, nulls); |
| } |
| |
| |
| /** |
| * Init fields using base as appropriate, but does not initialize aQueryObject field. |
| * |
| * @param base The base value for all fields. Fields are all set to a value using base as |
| * appropriate. |
| * @param useNulls If true, fill in nulls for those fields that can be set to null (to test null |
| * values), if false, then use a valid value (to test non-null values). |
| */ |
| public void fillInBaseValues(long base, boolean useNulls) { |
| final int maxCollectionSize = 100; |
| aChar = (char) base; |
| aBoolean = true; |
| aByte = (byte) base; |
| aShort = (short) base; |
| anInt = (int) base; |
| aLong = base; |
| aFloat = base; |
| aDouble = base; |
| aDate = new Date(base); |
| aString = "" + base; |
| if (useNulls) { |
| aDate = null; |
| aString = null; |
| anObject = null; |
| aMap = null; |
| aCollection = null; |
| // aRegion = null; |
| aBooleanArray = null; |
| aCharArray = null; |
| aByteArray = null; |
| aShortArray = null; |
| anIntArray = null; |
| aLongArray = null; |
| aFloatArray = null; |
| aDoubleArray = null; |
| anObjectArray = null; |
| anArrayOfByteArray = null; |
| } else { |
| int desiredCollectionSize = (int) Math.min(base, maxCollectionSize); |
| anObject = new SimpleClass((int) base, (byte) base); |
| aMap = new HashMap(); |
| aCollection = new ArrayList(); |
| aBooleanArray = new boolean[desiredCollectionSize]; |
| aCharArray = new char[desiredCollectionSize]; |
| aByteArray = new byte[desiredCollectionSize]; |
| aShortArray = new short[desiredCollectionSize]; |
| anIntArray = new int[desiredCollectionSize]; |
| aLongArray = new long[desiredCollectionSize]; |
| aFloatArray = new float[desiredCollectionSize]; |
| aDoubleArray = new double[desiredCollectionSize]; |
| aStringArray = new String[desiredCollectionSize]; |
| anObjectArray = new Object[desiredCollectionSize]; |
| anArrayOfByteArray = new byte[desiredCollectionSize][desiredCollectionSize]; |
| if (desiredCollectionSize > 0) { |
| for (int i = 0; i < desiredCollectionSize - 1; i++) { |
| aMap.put(i, i); |
| aCollection.add(i); |
| aBooleanArray[i] = (i % 2) == 0; |
| aCharArray[i] = (char) (i); |
| aByteArray[i] = (byte) (i); |
| aShortArray[i] = (short) i; |
| anIntArray[i] = i; |
| aLongArray[i] = i; |
| aFloatArray[i] = i; |
| aDoubleArray[i] = i; |
| aStringArray[i] = "" + i; |
| anObjectArray[i] = anObject; |
| anArrayOfByteArray[i] = aByteArray; |
| } |
| // now add the last value, using base if possible |
| aMap.put(base, base); |
| aCollection.add(base); |
| aBooleanArray[desiredCollectionSize - 1] = true; |
| aCharArray[desiredCollectionSize - 1] = (char) base; |
| aByteArray[desiredCollectionSize - 1] = (byte) base; |
| aShortArray[desiredCollectionSize - 1] = (short) base; |
| anIntArray[desiredCollectionSize - 1] = (int) base; |
| aLongArray[desiredCollectionSize - 1] = base; |
| aFloatArray[desiredCollectionSize - 1] = base; |
| aDoubleArray[desiredCollectionSize - 1] = base; |
| aStringArray[desiredCollectionSize - 1] = "" + base; |
| anObjectArray[desiredCollectionSize - 1] = anObject; |
| // aRegion = CacheHelper.getCache().rootRegions().iterator().next(); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see java.lang.Object#toString() |
| */ |
| @Override |
| public String toString() { |
| return getClass().getName() + " [aChar=" + this.aChar + ", aBoolean=" + this.aBoolean |
| + ", aByte=" + this.aByte + ", aShort=" + this.aShort + ", anInt=" + this.anInt |
| + ", aLong=" + this.aLong + ", aFloat=" + this.aFloat + ", aDouble=" + this.aDouble |
| + ", aDate=" + this.aDate + ", aString=" + this.aString + ", anObject=" + this.anObject |
| + ", aMap=" + this.aMap + ", aCollection=" + this.aCollection + ", aBooleanArray=" |
| + Arrays.toString(this.aBooleanArray) + ", aCharArray=" + Arrays.toString(this.aCharArray) |
| + ", aByteArray=" + Arrays.toString(this.aByteArray) + ", aShortArray=" |
| + Arrays.toString(this.aShortArray) + ", anIntArray=" + Arrays.toString(this.anIntArray) |
| + ", aLongArray=" + Arrays.toString(this.aLongArray) + ", aFloatArray=" |
| + Arrays.toString(this.aFloatArray) + ", aDoubleArray=" |
| + Arrays.toString(this.aDoubleArray) + ", aStringArray=" |
| + Arrays.toString(this.aStringArray) + ", anObjectArray=" |
| + Arrays.toString(this.anObjectArray) + ", anArrayOfByteArray=" |
| + Arrays.toString(this.anArrayOfByteArray) + "]"; |
| } |
| |
| @Override |
| public int hashCode() { |
| return 37; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (!(o instanceof BasicAllFieldTypes)) { |
| return false; |
| } |
| BasicAllFieldTypes other = (BasicAllFieldTypes) o; |
| if (this.aChar != other.aChar) { |
| System.out.println("!= aChar"); |
| return false; |
| } |
| if (this.aByte != other.aByte) { |
| System.out.println("!= aByte"); |
| return false; |
| } |
| if (this.aBoolean != other.aBoolean) { |
| System.out.println("!= aBoolean"); |
| return false; |
| } |
| if (this.aShort != other.aShort) { |
| System.out.println("!= aShort"); |
| return false; |
| } |
| if (this.anInt != other.anInt) { |
| System.out.println("!= anInt"); |
| return false; |
| } |
| if (this.aLong != other.aLong) { |
| System.out.println("!= aLong"); |
| return false; |
| } |
| if (this.aFloat != other.aFloat) { |
| System.out.println("!= aFloat"); |
| return false; |
| } |
| if (this.aDouble != other.aDouble) { |
| System.out.println("!= aDouble"); |
| return false; |
| } |
| if (!basicEquals(this.aDate, other.aDate)) { |
| System.out.println("!= aDate"); |
| return false; |
| } |
| if (!basicEquals(this.aString, other.aString)) { |
| System.out.println("!= aString"); |
| return false; |
| } |
| if (!basicEquals(this.anObject, other.anObject)) { |
| System.out.println("!= nObject"); |
| return false; |
| } |
| if (!basicEquals(this.aMap, other.aMap)) { |
| System.out.println("!= aMap"); |
| return false; |
| } |
| if (!basicEquals(this.aCollection, other.aCollection)) { |
| System.out.println("!= aCollection"); |
| return false; |
| } |
| // if (!basicEquals(this.aRegion, other.aRegion)) { |
| // return false; |
| // } |
| if (!Arrays.equals(this.aBooleanArray, other.aBooleanArray)) { |
| System.out.println("!= boolean[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aCharArray, other.aCharArray)) { |
| System.out.println("!= char[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aByteArray, other.aByteArray)) { |
| System.out.println("!= byte[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aShortArray, other.aShortArray)) { |
| System.out.println("!= short[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.anIntArray, other.anIntArray)) { |
| System.out.println("!= int[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aLongArray, other.aLongArray)) { |
| System.out.println("!= long[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aFloatArray, other.aFloatArray)) { |
| System.out.println("!= float[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aDoubleArray, other.aDoubleArray)) { |
| System.out.println("!= double[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.aStringArray, other.aStringArray)) { |
| System.out.println("!= String[]"); |
| return false; |
| } |
| if (!Arrays.equals(this.anObjectArray, other.anObjectArray)) { |
| System.out.println("!= Object[]"); |
| return false; |
| } |
| if (!byteArrayofArraysEqual(this.anArrayOfByteArray, other.anArrayOfByteArray)) { |
| System.out.println("!= byte[][]"); |
| return false; |
| } |
| return true; |
| } |
| |
| private boolean byteArrayofArraysEqual(byte[][] o1, byte[][] o2) { |
| if (o1 == null) { |
| return o2 == null; |
| } else if (o2 == null) { |
| return false; |
| } else { |
| if (o1.length != o2.length) { |
| return false; |
| } |
| for (int i = 0; i < o1.length; i++) { |
| if (!Arrays.equals(o1[i], o2[i])) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| private boolean basicEquals(Object o1, Object o2) { |
| if (o1 == null) { |
| return o2 == null; |
| } else if (o2 == null) { |
| return false; |
| } else { |
| return o1.equals(o2); |
| } |
| } |
| |
| } |
| |
| @Test |
| public void testVariableFields() throws Exception { |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(new VariableFields(1), out); |
| try { |
| DataSerializer.writeObject(new VariableFields(2), out); |
| throw new RuntimeException("expected ToDataException"); |
| } catch (ToDataException expected) { |
| if (!(expected.getCause() instanceof PdxSerializationException)) { |
| throw new RuntimeException("expected cause to be PdxSerializationException"); |
| } |
| } |
| try { |
| DataSerializer.writeObject(new VariableFields(0), out); |
| throw new RuntimeException("expected PdxSerializationException"); |
| } catch (PdxSerializationException expected) { |
| } |
| try { |
| DataSerializer.writeObject(new VariableFields(1, Object.class), out); |
| throw new RuntimeException("expected ToDataException"); |
| } catch (ToDataException expected) { |
| if (!(expected.getCause() instanceof PdxSerializationException)) { |
| throw new RuntimeException("expected cause to be PdxSerializationException"); |
| } |
| } |
| // TODO also test marking different identity fields. |
| } |
| |
| public static class VariableFields implements PdxSerializable { |
| |
| private Class fieldType = String.class; |
| private int fieldCount; |
| |
| public VariableFields(int fieldCount) { |
| this.fieldCount = fieldCount; |
| } |
| |
| public VariableFields(int fieldCount, Class fieldType) { |
| this.fieldCount = fieldCount; |
| this.fieldType = fieldType; |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| ((PdxWriterImpl) writer).setDoExtraValidation(true); |
| writer.writeInt("fieldCount", this.fieldCount); |
| for (int i = 0; i < this.fieldCount; i++) { |
| writer.writeField("f" + i, null, this.fieldType); |
| } |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| throw new IllegalStateException("should never be called"); |
| } |
| |
| } |
| public static class AllFieldTypes extends BasicAllFieldTypes implements PdxSerializable { |
| |
| public AllFieldTypes() { |
| super(); |
| } |
| |
| public AllFieldTypes(long base, boolean nulls) { |
| super(base, nulls); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.geode.pdx.PdxSerializable#toData(org.apache.geode. pdx.PdxWriter) |
| */ |
| @Override |
| public void toData(PdxWriter out) { |
| new BasicAllFieldTypesPdxSerializer().toData(this, out); |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.apache.geode.pdx.PdxSerializable#fromData(org.apache.geode .pdx.PdxReader) |
| */ |
| @Override |
| public void fromData(PdxReader in) { |
| new BasicAllFieldTypesPdxSerializer().fillInData(in, this); |
| } |
| } |
| |
| public static class BasicAllFieldTypesPdxSerializer implements PdxSerializer { |
| |
| @Override |
| public boolean toData(Object o, PdxWriter out) { |
| if (o instanceof BasicAllFieldTypes) { |
| BasicAllFieldTypes pdx = (BasicAllFieldTypes) o; |
| // extra fields for this version |
| out.writeChar("aChar", pdx.aChar); |
| out.writeBoolean("aBoolean", pdx.aBoolean); |
| out.writeByte("aByte", pdx.aByte); |
| out.writeShort("aShort", pdx.aShort); |
| out.writeInt("anInt", pdx.anInt); |
| out.writeLong("aLong", pdx.aLong); |
| out.writeFloat("aFloat", pdx.aFloat); |
| out.writeDouble("aDouble", pdx.aDouble); |
| out.writeDate("aDate", pdx.aDate); |
| out.writeString("aString", pdx.aString); |
| out.writeObject("anObject", pdx.anObject); |
| out.writeObject("aMap", pdx.aMap); |
| out.writeObject("aCollection", pdx.aCollection); |
| out.writeBooleanArray("aBooleanArray", pdx.aBooleanArray); |
| out.writeCharArray("aCharArray", pdx.aCharArray); |
| out.writeByteArray("aByteArray", pdx.aByteArray); |
| out.writeShortArray("aShortArray", pdx.aShortArray); |
| out.writeIntArray("anIntArray", pdx.anIntArray); |
| out.writeLongArray("aLongArray", pdx.aLongArray); |
| out.writeFloatArray("aFloatArray", pdx.aFloatArray); |
| out.writeDoubleArray("aDoubleArray", pdx.aDoubleArray); |
| out.writeStringArray("aStringArray", pdx.aStringArray); |
| out.writeObjectArray("anObjectArray", pdx.anObjectArray); |
| out.writeArrayOfByteArrays("anArrayOfByteArray", pdx.anArrayOfByteArray); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public Object fromData(Class<?> clazz, PdxReader in) { |
| if (BasicAllFieldTypes.class.isAssignableFrom(clazz)) { |
| BasicAllFieldTypes pdx = new BasicAllFieldTypes(); |
| fillInData(in, pdx); |
| return pdx; |
| } else { |
| return null; |
| } |
| } |
| |
| public void fillInData(PdxReader in, BasicAllFieldTypes pdx) { |
| // extra fields for this version |
| try { |
| in.readBoolean("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readByte("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readShort("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readInt("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readLong("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readFloat("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readDouble("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readDate("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readString("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readObject("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readBooleanArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readCharArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readByteArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readShortArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readIntArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readLongArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readFloatArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readDoubleArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readStringArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readObjectArray("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readArrayOfByteArrays("aChar"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| try { |
| in.readChar("aBoolean"); |
| throw new RuntimeException("expected PdxFieldTypeMismatchException"); |
| } catch (PdxFieldTypeMismatchException expected) { |
| // expected |
| } |
| pdx.aChar = in.readChar("aChar"); |
| pdx.aBoolean = in.readBoolean("aBoolean"); |
| pdx.aByte = in.readByte("aByte"); |
| pdx.aShort = in.readShort("aShort"); |
| pdx.anInt = in.readInt("anInt"); |
| pdx.aLong = in.readLong("aLong"); |
| pdx.aFloat = in.readFloat("aFloat"); |
| pdx.aDouble = in.readDouble("aDouble"); |
| pdx.aDate = in.readDate("aDate"); |
| pdx.aString = in.readString("aString"); |
| pdx.anObject = in.readObject("anObject"); |
| pdx.aMap = (Map) in.readObject("aMap"); |
| pdx.aCollection = (Collection) in.readObject("aCollection"); |
| pdx.aBooleanArray = in.readBooleanArray("aBooleanArray"); |
| pdx.aCharArray = in.readCharArray("aCharArray"); |
| pdx.aByteArray = in.readByteArray("aByteArray"); |
| pdx.aShortArray = in.readShortArray("aShortArray"); |
| pdx.anIntArray = in.readIntArray("anIntArray"); |
| pdx.aLongArray = in.readLongArray("aLongArray"); |
| pdx.aFloatArray = in.readFloatArray("aFloatArray"); |
| pdx.aDoubleArray = in.readDoubleArray("aDoubleArray"); |
| pdx.aStringArray = in.readStringArray("aStringArray"); |
| pdx.anObjectArray = in.readObjectArray("anObjectArray"); |
| pdx.anArrayOfByteArray = in.readArrayOfByteArrays("anArrayOfByteArray"); |
| } |
| |
| } |
| |
| public static class AllFieldTypesRF extends AllFieldTypes { |
| public AllFieldTypesRF(long l, boolean b) { |
| super(l, b); |
| } |
| |
| public AllFieldTypesRF() { |
| super(); |
| } |
| |
| @Override |
| public void fromData(PdxReader in) { |
| aChar = (Character) in.readField("aChar"); |
| aBoolean = (Boolean) in.readField("aBoolean"); |
| aByte = (Byte) in.readField("aByte"); |
| aShort = (Short) in.readField("aShort"); |
| anInt = (Integer) in.readField("anInt"); |
| aLong = (Long) in.readField("aLong"); |
| aFloat = (Float) in.readField("aFloat"); |
| aDouble = (Double) in.readField("aDouble"); |
| aDate = (Date) in.readField("aDate"); |
| aString = (String) in.readField("aString"); |
| anObject = in.readField("anObject"); |
| aMap = (Map) in.readField("aMap"); |
| aCollection = (Collection) in.readField("aCollection"); |
| aBooleanArray = (boolean[]) in.readField("aBooleanArray"); |
| aCharArray = (char[]) in.readField("aCharArray"); |
| aByteArray = (byte[]) in.readField("aByteArray"); |
| aShortArray = (short[]) in.readField("aShortArray"); |
| anIntArray = (int[]) in.readField("anIntArray"); |
| aLongArray = (long[]) in.readField("aLongArray"); |
| aFloatArray = (float[]) in.readField("aFloatArray"); |
| aDoubleArray = (double[]) in.readField("aDoubleArray"); |
| aStringArray = (String[]) in.readField("aStringArray"); |
| anObjectArray = (Object[]) in.readField("anObjectArray"); |
| anArrayOfByteArray = (byte[][]) in.readField("anArrayOfByteArray"); |
| } |
| |
| } |
| |
| public static class AllFieldTypesWF extends AllFieldTypes { |
| public AllFieldTypesWF(long l, boolean b) { |
| super(l, b); |
| } |
| |
| public AllFieldTypesWF() { |
| super(); |
| } |
| |
| @Override |
| public void toData(PdxWriter out) { |
| out.writeField("aChar", this.aChar, char.class); |
| out.writeField("aBoolean", this.aBoolean, boolean.class); |
| out.writeField("aByte", this.aByte, byte.class); |
| out.writeField("aShort", this.aShort, short.class); |
| out.writeField("anInt", this.anInt, int.class); |
| out.writeField("aLong", this.aLong, long.class); |
| out.writeField("aFloat", this.aFloat, float.class); |
| out.writeField("aDouble", this.aDouble, double.class); |
| out.writeField("aDate", this.aDate, Date.class); |
| out.writeField("aString", this.aString, String.class); |
| out.writeField("anObject", this.anObject, Object.class); |
| out.writeField("aMap", this.aMap, Map.class); |
| out.writeField("aCollection", this.aCollection, Collection.class); |
| out.writeField("aBooleanArray", this.aBooleanArray, boolean[].class); |
| out.writeField("aCharArray", this.aCharArray, char[].class); |
| out.writeField("aByteArray", this.aByteArray, byte[].class); |
| out.writeField("aShortArray", this.aShortArray, short[].class); |
| out.writeField("anIntArray", this.anIntArray, int[].class); |
| out.writeField("aLongArray", this.aLongArray, long[].class); |
| out.writeField("aFloatArray", this.aFloatArray, float[].class); |
| out.writeField("aDoubleArray", this.aDoubleArray, double[].class); |
| out.writeField("aStringArray", this.aStringArray, String[].class); |
| out.writeField("anObjectArray", this.anObjectArray, Object[].class); |
| // TODO test other types of Object[] like SimpleClass[]. |
| out.writeField("anArrayOfByteArray", this.anArrayOfByteArray, byte[][].class); |
| } |
| } |
| |
| private byte[] createBlob(Object o) throws IOException { |
| HeapDataOutputStream out = new HeapDataOutputStream(Version.CURRENT); |
| DataSerializer.writeObject(o, out); |
| return out.toByteArray(); |
| } |
| |
| private <T> T deblob(byte[] blob) throws IOException, ClassNotFoundException { |
| return (T) DataSerializer.readObject(new DataInputStream(new ByteArrayInputStream(blob))); |
| } |
| |
| /** |
| * Make sure that if a class adds a field that pdx serialization will preserve the extra field. |
| */ |
| @Test |
| public void testFieldAppend() throws Exception { |
| MyEvolvablePdx.setVersion(1); |
| MyEvolvablePdx pdx = new MyEvolvablePdx(7); |
| assertEquals(7, pdx.f1); |
| assertEquals(0, pdx.f2); |
| |
| MyEvolvablePdx.setVersion(2); |
| pdx = new MyEvolvablePdx(7); |
| assertEquals(7, pdx.f1); |
| assertEquals(8, pdx.f2); |
| byte[] v2actual = createBlob(pdx); |
| int v2typeId = getBlobPdxTypeId(v2actual); |
| |
| cache.getPdxRegistry().removeLocal(pdx); |
| MyEvolvablePdx.setVersion(1); |
| MyEvolvablePdx pdxv1 = deblob(v2actual); |
| assertEquals(7, pdxv1.f1); |
| assertEquals(0, pdxv1.f2); |
| |
| // now reserialize and make sure f2 is preserved |
| byte[] v1actual = createBlob(pdxv1); |
| assertEquals(v2typeId, getBlobPdxTypeId(v1actual)); |
| checkBytes(v2actual, v1actual); |
| // serialize one more time to make sure internal cache works ok |
| v1actual = createBlob(pdxv1); |
| assertEquals(v2typeId, getBlobPdxTypeId(v1actual)); |
| checkBytes(v2actual, v1actual); |
| // make sure CopyHelper preserves extra fields |
| MyEvolvablePdx pdxv1copy = CopyHelper.copy(pdxv1); |
| v1actual = createBlob(pdxv1copy); |
| assertEquals(v2typeId, getBlobPdxTypeId(v1actual)); |
| checkBytes(v2actual, v1actual); |
| |
| MyEvolvablePdx.setVersion(2); |
| cache.getPdxRegistry().removeLocal(pdx); |
| MyEvolvablePdx pdxv2 = deblob(v1actual); |
| assertEquals(7, pdxv2.f1); |
| assertEquals(8, pdxv2.f2); |
| // make sure we can dserialize a second time with the same results |
| pdxv2 = deblob(v1actual); |
| assertEquals(7, pdxv2.f1); |
| assertEquals(8, pdxv2.f2); |
| } |
| |
| @Test |
| public void testFieldInsert() throws Exception { |
| MyEvolvablePdx.setVersion(1); |
| MyEvolvablePdx pdx = new MyEvolvablePdx(7); |
| assertEquals(7, pdx.f1); |
| assertEquals(0, pdx.f2); |
| |
| MyEvolvablePdx.setVersion(3); |
| pdx = new MyEvolvablePdx(7); |
| assertEquals(7, pdx.f1); |
| assertEquals(8, pdx.f2); |
| byte[] v3actual = createBlob(pdx); |
| int v3typeId = getBlobPdxTypeId(v3actual); |
| cache.getPdxRegistry().removeLocal(pdx); |
| MyEvolvablePdx.setVersion(1); |
| MyEvolvablePdx pdxv1 = deblob(v3actual); |
| assertEquals(7, pdxv1.f1); |
| assertEquals(0, pdxv1.f2); |
| |
| int numPdxTypes = getNumPdxTypes(); |
| // now reserialize and make sure f2 is preserved |
| byte[] v1actual = createBlob(pdxv1); |
| |
| int mergedTypeId = getBlobPdxTypeId(v1actual); |
| assertEquals(numPdxTypes + 1, getNumPdxTypes()); |
| TypeRegistry tr = cache.getPdxRegistry(); |
| PdxType v3Type = tr.getType(v3typeId); |
| PdxType mergedType = tr.getType(mergedTypeId); |
| assertFalse(mergedType.equals(v3Type)); |
| assertTrue(mergedType.compatible(v3Type)); |
| |
| MyEvolvablePdx.setVersion(3); |
| cache.getPdxRegistry().removeLocal(pdxv1); |
| MyEvolvablePdx pdxv3 = deblob(v1actual); |
| assertEquals(7, pdxv3.f1); |
| assertEquals(8, pdxv3.f2); |
| } |
| |
| @Test |
| public void testFieldRemove() throws Exception { |
| // this test pretends that version 1 is newer than version2 |
| // so it look like a field was removed. |
| MyEvolvablePdx.setVersion(1); |
| MyEvolvablePdx pdx = new MyEvolvablePdx(7); |
| assertEquals(7, pdx.f1); |
| assertEquals(0, pdx.f2); |
| |
| byte[] v1actual = createBlob(pdx); |
| int v1typeId = getBlobPdxTypeId(v1actual); |
| |
| cache.getPdxRegistry().removeLocal(pdx); |
| MyEvolvablePdx.setVersion(2); |
| MyEvolvablePdx pdxv2 = deblob(v1actual); |
| assertEquals(7, pdxv2.f1); |
| assertEquals(0, pdxv2.f2); |
| pdxv2.f2 = 23; |
| |
| int numPdxTypes = getNumPdxTypes(); |
| // now reserialize and make sure it is version2 and not version1 |
| byte[] v2actual = createBlob(pdxv2); |
| int v2typeId = getBlobPdxTypeId(v2actual); |
| assertEquals(numPdxTypes + 1, getNumPdxTypes()); |
| |
| TypeRegistry tr = cache.getPdxRegistry(); |
| PdxType v2Type = tr.getType(v2typeId); |
| PdxType v1Type = tr.getType(v1typeId); |
| assertFalse(v1Type.equals(v2Type)); |
| assertFalse(v1Type.compatible(v2Type)); |
| assertNotNull(v1Type.getPdxField("f1")); |
| assertNull(v1Type.getPdxField("f2")); |
| assertNotNull(v2Type.getPdxField("f1")); |
| assertNotNull(v2Type.getPdxField("f2")); |
| |
| MyEvolvablePdx.setVersion(1); |
| cache.getPdxRegistry().removeLocal(pdx); |
| MyEvolvablePdx pdxv3 = deblob(v2actual); |
| assertEquals(7, pdxv3.f1); |
| assertEquals(0, pdxv3.f2); |
| } |
| |
| private int getBlobPdxTypeId(byte[] blob) { |
| ByteBuffer bb = ByteBuffer.wrap(blob); |
| // skip byte for PDX dscode and integer for pdx length |
| return bb.getInt(DataSize.BYTE_SIZE + DataSize.INTEGER_SIZE); |
| } |
| |
| public static class MyEvolvablePdx implements PdxSerializable { |
| private static int version = 1; |
| |
| private static int getVersion() { |
| return version; |
| } |
| |
| private static void setVersion(int v) { |
| version = v; |
| } |
| |
| public int f1; |
| public int f2; |
| |
| public MyEvolvablePdx(int base) { |
| this.f1 = base; |
| base++; |
| if (getVersion() >= 2) { |
| this.f2 = base; |
| base++; |
| } |
| } |
| |
| public MyEvolvablePdx() { |
| // need for pdx deserialization |
| } |
| |
| @Override |
| public void toData(PdxWriter writer) { |
| if (getVersion() == 3) { |
| writer.writeInt("f2", this.f2); |
| } |
| writer.writeInt("f1", this.f1); |
| if (getVersion() == 2) { |
| writer.writeInt("f2", this.f2); |
| } |
| } |
| |
| @Override |
| public void fromData(PdxReader reader) { |
| if (getVersion() == 3) { |
| this.f2 = reader.readInt("f2"); |
| } |
| this.f1 = reader.readInt("f1"); |
| if (getVersion() == 2) { |
| this.f2 = reader.readInt("f2"); |
| } |
| } |
| } |
| |
| |
| /** PlainOldSerializable */ |
| public static class POS implements java.io.Serializable { |
| int f; |
| |
| public POS(int i) { |
| this.f = i; |
| } |
| |
| public int hashCode() { |
| return f; |
| } |
| |
| public boolean equals(Object obj) { |
| if (obj == null) |
| return false; |
| if (!(obj instanceof POS)) |
| return false; |
| POS other = (POS) obj; |
| return this.f == other.f; |
| } |
| } |
| } |