/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.kernel.io; import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream; import com.liferay.portal.kernel.test.rule.CodeCoverageAssertor; import com.liferay.portal.kernel.util.ClassLoaderPool; import com.liferay.portal.kernel.util.PortalClassLoaderUtil; import com.liferay.portal.kernel.util.StringPool; import java.io.ObjectOutputStream; import java.io.StreamCorruptedException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.DoubleBuffer; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.nio.ShortBuffer; import java.util.Date; import java.util.List; import java.util.Random; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; /** * @author Shuyang Zhou */ public class DeserializerTest { @ClassRule public static final CodeCoverageAssertor codeCoverageAssertor = new CodeCoverageAssertor() { @Override public void appendAssertClasses(List<Class<?>> assertClasses) { assertClasses.add(AnnotatedObjectOutputStream.class); assertClasses.add(ProtectedAnnotatedObjectInputStream.class); } }; @Before public void setUp() { Class<?> clazz = getClass(); PortalClassLoaderUtil.setClassLoader(clazz.getClassLoader()); } @Test public void testBufferInputStream() { byte[] data = new byte[_COUNT]; _random.nextBytes(data); Deserializer deserializer = new Deserializer(ByteBuffer.wrap(data)); Deserializer.BufferInputStream bufferInputStream = deserializer.new BufferInputStream(); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(data[i], bufferInputStream.read()); } deserializer = new Deserializer(ByteBuffer.wrap(data)); bufferInputStream = deserializer.new BufferInputStream(); int size1 = _COUNT * 2 / 3; int size2 = _COUNT - size1; byte[] newBytes = new byte[size1]; int count = bufferInputStream.read(newBytes); Assert.assertEquals(size1, count); for (int i = 0; i < size1; i++) { Assert.assertEquals(data[i], newBytes[i]); } newBytes = new byte[size1]; count = bufferInputStream.read(newBytes); Assert.assertEquals(size2, count); for (int i = 0; i < size2; i++) { Assert.assertEquals(data[i + size1], newBytes[i]); } } @Test public void testDetectBufferUnderflow() { ByteBuffer byteBuffer = ByteBuffer.allocate(4); Deserializer deserializer = new Deserializer(byteBuffer); deserializer.detectBufferUnderflow(4); try { deserializer.detectBufferUnderflow(5); Assert.fail(); } catch (IllegalStateException ise) { Assert.assertEquals("Buffer underflow", ise.getMessage()); } } @Test public void testReadBoolean() { byte[] bytes = new byte[_COUNT]; for (int i = 0; i < _COUNT; i++) { bytes[i] = _random.nextBoolean() ? (byte)1 : (byte)0; } ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { if (bytes[i] == 0) { Assert.assertFalse(deserializer.readBoolean()); } else { Assert.assertTrue(deserializer.readBoolean()); } } } @Test public void testReadByte() { byte[] bytes = new byte[_COUNT]; _random.nextBytes(bytes); ByteBuffer byteBuffer = ByteBuffer.wrap(bytes); Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(bytes[i], deserializer.readByte()); } } @Test public void testReadChar() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 2); byteBuffer.order(ByteOrder.BIG_ENDIAN); CharBuffer charBuffer = byteBuffer.asCharBuffer(); char[] chars = new char[_COUNT]; for (int i = 0; i < _COUNT; i++) { chars[i] = (char)_random.nextInt(); charBuffer.put(chars[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(chars[i], deserializer.readChar()); } } @Test public void testReadDouble() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 8); byteBuffer.order(ByteOrder.BIG_ENDIAN); DoubleBuffer doubleBuffer = byteBuffer.asDoubleBuffer(); double[] doubles = new double[_COUNT]; for (int i = 0; i < _COUNT; i++) { doubles[i] = _random.nextDouble(); doubleBuffer.put(doubles[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals( (Double)doubles[i], (Double)deserializer.readDouble()); } } @Test public void testReadFloat() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 4); byteBuffer.order(ByteOrder.BIG_ENDIAN); FloatBuffer floatBuffer = byteBuffer.asFloatBuffer(); float[] floats = new float[_COUNT]; for (int i = 0; i < _COUNT; i++) { floats[i] = _random.nextFloat(); floatBuffer.put(floats[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals( (Float)floats[i], (Float)deserializer.readFloat()); } } @Test public void testReadInt() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 4); byteBuffer.order(ByteOrder.BIG_ENDIAN); IntBuffer intBuffer = byteBuffer.asIntBuffer(); int[] ints = new int[_COUNT]; for (int i = 0; i < _COUNT; i++) { ints[i] = _random.nextInt(); intBuffer.put(ints[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(ints[i], deserializer.readInt()); } } @Test public void testReadLong() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 8); byteBuffer.order(ByteOrder.BIG_ENDIAN); LongBuffer longBuffer = byteBuffer.asLongBuffer(); long[] longs = new long[_COUNT]; for (int i = 0; i < _COUNT; i++) { longs[i] = _random.nextLong(); longBuffer.put(longs[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(longs[i], deserializer.readLong()); } } @Test public void testReadObjectBoolean() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(2); byteBuffer.put(SerializationConstants.TC_BOOLEAN); byteBuffer.put((byte)1); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Boolean); Assert.assertSame(Boolean.TRUE, object); } @Test public void testReadObjectByte() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(2); byteBuffer.put(SerializationConstants.TC_BYTE); byteBuffer.put((byte)101); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Byte); Assert.assertSame(Byte.valueOf((byte)101), object); } @Test public void testReadObjectCharacter() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(3); byteBuffer.put(SerializationConstants.TC_CHARACTER); byteBuffer.putChar('a'); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Character); Assert.assertSame(Character.valueOf('a'), object); } @Test public void testReadObjectClassWithBlankContextName() throws Exception { Class<?> clazz = getClass(); String className = clazz.getName(); ByteBuffer byteBuffer = ByteBuffer.allocate(className.length() + 11); byteBuffer.put(SerializationConstants.TC_CLASS); byteBuffer.put((byte)1); byteBuffer.putInt(0); byteBuffer.put((byte)1); byteBuffer.putInt(className.length()); byteBuffer.put(className.getBytes(StringPool.UTF8)); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); ClassLoaderPool.register(StringPool.BLANK, clazz.getClassLoader()); try { Assert.assertSame(clazz, deserializer.readObject()); } finally { ClassLoaderPool.unregister(clazz.getClassLoader()); } } @Test public void testReadObjectClassWithNullContextName() throws Exception { Class<?> clazz = getClass(); String className = clazz.getName(); String contextName = StringPool.NULL; ByteBuffer byteBuffer = ByteBuffer.allocate( className.length() + contextName.length() + 11); byteBuffer.put(SerializationConstants.TC_CLASS); byteBuffer.put((byte)1); byteBuffer.putInt(contextName.length()); byteBuffer.put(contextName.getBytes(StringPool.UTF8)); byteBuffer.put((byte)1); byteBuffer.putInt(className.length()); byteBuffer.put(className.getBytes(StringPool.UTF8)); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Class<?> readClass = deserializer.readObject(); Assert.assertSame(clazz, readClass); } @Test public void testReadObjectDouble() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(9); byteBuffer.put(SerializationConstants.TC_DOUBLE); byteBuffer.putDouble(17.58D); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Double); Assert.assertEquals(17.58D, object); } @Test public void testReadObjectFloat() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(5); byteBuffer.put(SerializationConstants.TC_FLOAT); byteBuffer.putFloat(17.58F); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Float); Assert.assertEquals(17.58F, object); } @Test public void testReadObjectInteger() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(5); byteBuffer.put(SerializationConstants.TC_INTEGER); byteBuffer.putInt(101); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Integer); Assert.assertSame(Integer.valueOf(101), object); } @Test public void testReadObjectLong() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(9); byteBuffer.put(SerializationConstants.TC_LONG); byteBuffer.putLong(101); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Long); Assert.assertSame(Long.valueOf(101), object); } @Test public void testReadObjectNull() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(1); byteBuffer.put(SerializationConstants.TC_NULL); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertNull(object); } @Test public void testReadObjectOrdinary() throws Exception { UnsyncByteArrayOutputStream unsyncByteArrayOutputStream = new UnsyncByteArrayOutputStream(); unsyncByteArrayOutputStream.write(SerializationConstants.TC_OBJECT); ObjectOutputStream objectOutputStream = new AnnotatedObjectOutputStream( unsyncByteArrayOutputStream); Date date = new Date(123456); objectOutputStream.writeObject(date); ByteBuffer byteBuffer = unsyncByteArrayOutputStream.unsafeGetByteBuffer(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Date); Assert.assertEquals(date, object); } @Test public void testReadObjectOrdinaryNPE() throws Exception { UnsyncByteArrayOutputStream unsyncByteArrayOutputStream = new UnsyncByteArrayOutputStream(); unsyncByteArrayOutputStream.write(SerializationConstants.TC_OBJECT); unsyncByteArrayOutputStream.write(1); unsyncByteArrayOutputStream.write(new byte[4]); ObjectOutputStream objectOutputStream = new ObjectOutputStream( unsyncByteArrayOutputStream); Date date = new Date(123456); objectOutputStream.writeObject(date); ByteBuffer byteBuffer = unsyncByteArrayOutputStream.unsafeGetByteBuffer(); // Corrupt magic header byteBuffer.put(6, (byte)0xFF); Deserializer deserializer = new Deserializer(byteBuffer); try { deserializer.readObject(); Assert.fail(); } catch (RuntimeException re) { Assert.assertTrue( re.getCause() instanceof StreamCorruptedException); } } @Test public void testReadObjectShort() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(3); byteBuffer.put(SerializationConstants.TC_SHORT); byteBuffer.putShort((short)101); byteBuffer.flip(); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof Short); Assert.assertSame(Short.valueOf((short)101), object); } @Test public void testReadObjectString() throws ClassNotFoundException { String asciiString = "abcdefghijklmn"; byte[] buffer = new byte[asciiString.length() + 6]; buffer[0] = SerializationConstants.TC_STRING; buffer[1] = 1; BigEndianCodec.putInt(buffer, 2, asciiString.length()); for (int i = 0; i < asciiString.length(); i++) { buffer[6 + i] = (byte)asciiString.charAt(i); } ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); Deserializer deserializer = new Deserializer(byteBuffer); Object object = deserializer.readObject(); Assert.assertTrue(object instanceof String); Assert.assertEquals(asciiString, object); String nonAsciiString = "非ASCII Code中文测试"; buffer = new byte[nonAsciiString.length() * 2 + 6]; buffer[0] = SerializationConstants.TC_STRING; buffer[1] = 0; BigEndianCodec.putInt(buffer, 2, nonAsciiString.length()); for (int i = 0; i < nonAsciiString.length(); i++) { BigEndianCodec.putChar(buffer, 6 + i * 2, nonAsciiString.charAt(i)); } byteBuffer = ByteBuffer.wrap(buffer); deserializer = new Deserializer(byteBuffer); object = deserializer.readObject(); Assert.assertTrue(object instanceof String); Assert.assertEquals(nonAsciiString, object); } @Test public void testReadObjectUnknowTCCode() throws ClassNotFoundException { ByteBuffer byteBuffer = ByteBuffer.allocate(1); byteBuffer.put((byte)12); Deserializer deserializer = new Deserializer(byteBuffer); try { deserializer.readObject(); } catch (IllegalStateException ise) { Assert.assertEquals("Unkown TC code 12", ise.getMessage()); } } @Test public void testReadShort() { ByteBuffer byteBuffer = ByteBuffer.allocate(_COUNT * 2); byteBuffer.order(ByteOrder.BIG_ENDIAN); ShortBuffer shortBuffer = byteBuffer.asShortBuffer(); short[] shorts = new short[_COUNT]; for (int i = 0; i < _COUNT; i++) { shorts[i] = (short)_random.nextInt(); shortBuffer.put(shorts[i]); } Deserializer deserializer = new Deserializer(byteBuffer); for (int i = 0; i < _COUNT; i++) { Assert.assertEquals(shorts[i], deserializer.readShort()); } } @Test public void testReadString() { String asciiString = "abcdefghijklmn"; byte[] buffer = new byte[asciiString.length() + 5]; buffer[0] = 1; BigEndianCodec.putInt(buffer, 1, asciiString.length()); for (int i = 0; i < asciiString.length(); i++) { buffer[5 + i] = (byte)asciiString.charAt(i); } ByteBuffer byteBuffer = ByteBuffer.wrap(buffer); Deserializer deserializer = new Deserializer(byteBuffer); String resultString = deserializer.readString(); Assert.assertEquals(asciiString, resultString); String nonAsciiString = "非ASCII Code中文测试"; buffer = new byte[nonAsciiString.length() * 2 + 5]; buffer[0] = 0; BigEndianCodec.putInt(buffer, 1, nonAsciiString.length()); for (int i = 0; i < nonAsciiString.length(); i++) { BigEndianCodec.putChar(buffer, 5 + i * 2, nonAsciiString.charAt(i)); } byteBuffer = ByteBuffer.wrap(buffer); deserializer = new Deserializer(byteBuffer); resultString = deserializer.readString(); Assert.assertEquals(nonAsciiString, resultString); } private static final int _COUNT = 1024; private final Random _random = new Random(); }