/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed 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 com.hazelcast.nio.serialization; import com.hazelcast.internal.serialization.InternalSerializationService; import com.hazelcast.internal.serialization.impl.DefaultSerializationServiceBuilder; import com.hazelcast.nio.BufferObjectDataInput; import com.hazelcast.nio.BufferObjectDataOutput; import com.hazelcast.spi.serialization.SerializationService; import com.hazelcast.test.HazelcastSerialClassRunner; import com.hazelcast.test.annotation.QuickTest; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import static com.hazelcast.nio.serialization.PortableTest.createNamedPortableClassDefinition; import static com.hazelcast.nio.serialization.PortableTest.createSerializationService; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @RunWith(HazelcastSerialClassRunner.class) @Category(QuickTest.class) public class PortableClassVersionTest { private static final int FACTORY_ID = TestSerializationConstants.PORTABLE_FACTORY_ID; @Test public void testDifferentClassVersions() { SerializationService serializationService = new DefaultSerializationServiceBuilder() .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortable(); } }).build(); SerializationService serializationService2 = new DefaultSerializationServiceBuilder() .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortableV2(); } }).build(); testDifferentClassVersions(serializationService, serializationService2); } @Test public void testDifferentClassAndServiceVersions() { SerializationService serializationService = new DefaultSerializationServiceBuilder().setPortableVersion(1) .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortable(); } }).build(); SerializationService serializationService2 = new DefaultSerializationServiceBuilder().setPortableVersion(2) .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortableV2(); } }).build(); testDifferentClassVersions(serializationService, serializationService2); } // used in EE, so needs to be package private static void testDifferentClassVersions(SerializationService serializationService, SerializationService serializationService2) { NamedPortable portableV1 = new NamedPortable("named-portable", 123); Data dataV1 = serializationService.toData(portableV1); NamedPortableV2 portableV2 = new NamedPortableV2("named-portable", 123, 500); Data dataV2 = serializationService2.toData(portableV2); NamedPortable v1FromV2 = serializationService.toObject(dataV2); assertEquals(portableV2.name, v1FromV2.name); assertEquals(portableV2.k, v1FromV2.k); NamedPortableV2 v2FromV1 = serializationService2.toObject(dataV1); assertEquals(portableV1.name, v2FromV1.name); assertEquals(portableV1.k, v2FromV1.k); assertNull(v2FromV1.v); } @Test public void testDifferentClassVersionsUsingDataWriteAndRead() throws Exception { InternalSerializationService serializationService = new DefaultSerializationServiceBuilder() .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortable(); } }).build(); InternalSerializationService serializationService2 = new DefaultSerializationServiceBuilder() .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortableV2(); } }).build(); testDifferentClassVersionsUsingDataWriteAndRead(serializationService, serializationService2); } @Test public void testDifferentClassAndServiceVersionsUsingDataWriteAndRead() throws Exception { InternalSerializationService serializationService = new DefaultSerializationServiceBuilder().setPortableVersion(1) .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortable(); } }).build(); InternalSerializationService serializationService2 = new DefaultSerializationServiceBuilder().setPortableVersion(2) .addPortableFactory(FACTORY_ID, new PortableFactory() { public Portable create(int classId) { return new NamedPortableV2(); } }).build(); testDifferentClassVersionsUsingDataWriteAndRead(serializationService, serializationService2); } // used in EE, so needs to be package private static void testDifferentClassVersionsUsingDataWriteAndRead(InternalSerializationService serializationService, InternalSerializationService serializationService2) throws Exception { NamedPortable portableV1 = new NamedPortable("portable-v1", 111); Data dataV1 = serializationService.toData(portableV1); // emulate socket write by writing data to stream BufferObjectDataOutput out = serializationService.createObjectDataOutput(1024); out.writeData(dataV1); byte[] bytes = out.toByteArray(); // emulate socket read by reading data from stream BufferObjectDataInput in = serializationService2.createObjectDataInput(bytes); dataV1 = in.readData(); // serialize new portable version NamedPortableV2 portableV2 = new NamedPortableV2("portable-v2", 123, 500); Data dataV2 = serializationService2.toData(portableV2); NamedPortable v1FromV2 = serializationService.toObject(dataV2); assertEquals(portableV2.name, v1FromV2.name); assertEquals(portableV2.k, v1FromV2.k); NamedPortableV2 v2FromV1 = serializationService2.toObject(dataV1); assertEquals(portableV1.name, v2FromV1.name); assertEquals(portableV1.k, v2FromV1.k); assertNull(v2FromV1.v); } @Test public void testPreDefinedDifferentVersionsWithInnerPortable() { InternalSerializationService serializationService = createSerializationService(1); serializationService.getPortableContext().registerClassDefinition(createInnerPortableClassDefinition(1)); InternalSerializationService serializationService2 = createSerializationService(2); serializationService2.getPortableContext().registerClassDefinition(createInnerPortableClassDefinition(2)); NamedPortable[] nn = new NamedPortable[1]; nn[0] = new NamedPortable("name", 123); InnerPortable inner = new InnerPortable(new byte[]{0, 1, 2}, new char[]{'c', 'h', 'a', 'r'}, new short[]{3, 4, 5}, new int[]{9, 8, 7, 6}, new long[]{0, 1, 5, 7, 9, 11}, new float[]{0.6543f, -3.56f, 45.67f}, new double[]{456.456, 789.789, 321.321}, nn); MainPortable mainWithInner = new MainPortable((byte) 113, true, 'x', (short) -500, 56789, -50992225L, 900.5678f, -897543.3678909d, "this is main portable object created for testing!", inner); testPreDefinedDifferentVersions(serializationService, serializationService2, mainWithInner); } @Test public void testPreDefinedDifferentVersionsWithNullInnerPortable() { InternalSerializationService serializationService = createSerializationService(1); serializationService.getPortableContext().registerClassDefinition(createInnerPortableClassDefinition(1)); InternalSerializationService serializationService2 = createSerializationService(2); serializationService2.getPortableContext().registerClassDefinition(createInnerPortableClassDefinition(2)); MainPortable mainWithNullInner = new MainPortable((byte) 113, true, 'x', (short) -500, 56789, -50992225L, 900.5678f, -897543.3678909d, "this is main portable object created for testing!", null); testPreDefinedDifferentVersions(serializationService, serializationService2, mainWithNullInner); } private static void testPreDefinedDifferentVersions(SerializationService serializationService, SerializationService serializationService2, MainPortable mainPortable) { Data data = serializationService.toData(mainPortable); assertEquals(mainPortable, serializationService2.toObject(data)); } // used in EE, so needs to be package private static ClassDefinition createInnerPortableClassDefinition(int portableVersion) { ClassDefinitionBuilder builder = new ClassDefinitionBuilder(FACTORY_ID, TestSerializationConstants.INNER_PORTABLE, portableVersion); builder.addByteArrayField("b"); builder.addCharArrayField("c"); builder.addShortArrayField("s"); builder.addIntArrayField("i"); builder.addLongArrayField("l"); builder.addFloatArrayField("f"); builder.addDoubleArrayField("d"); builder.addPortableArrayField("nn", createNamedPortableClassDefinition(portableVersion)); return builder.build(); } }