1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.lang3; 18 19 import static org.junit.jupiter.api.Assertions.assertArrayEquals; 20 import static org.junit.jupiter.api.Assertions.assertEquals; 21 import static org.junit.jupiter.api.Assertions.assertFalse; 22 import static org.junit.jupiter.api.Assertions.assertNotNull; 23 import static org.junit.jupiter.api.Assertions.assertNotSame; 24 import static org.junit.jupiter.api.Assertions.assertNull; 25 import static org.junit.jupiter.api.Assertions.assertSame; 26 import static org.junit.jupiter.api.Assertions.assertThrows; 27 import static org.junit.jupiter.api.Assertions.assertTrue; 28 29 import java.io.ByteArrayInputStream; 30 import java.io.ByteArrayOutputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.ObjectInputStream; 34 import java.io.ObjectOutputStream; 35 import java.io.OutputStream; 36 import java.io.Serializable; 37 import java.lang.reflect.Constructor; 38 import java.lang.reflect.Modifier; 39 import java.util.HashMap; 40 41 import org.junit.jupiter.api.BeforeEach; 42 import org.junit.jupiter.api.Test; 43 44 /** 45 * Unit tests {@link org.apache.commons.lang3.SerializationUtils}. 46 */ 47 public class SerializationUtilsTest extends AbstractLangTest { 48 49 static final String CLASS_NOT_FOUND_MESSAGE = "ClassNotFoundSerialization.readObject fake exception"; 50 protected static final String SERIALIZE_IO_EXCEPTION_MESSAGE = "Anonymous OutputStream I/O exception"; 51 52 private String iString; 53 private Integer iInteger; 54 private HashMap<Object, Object> iMap; 55 56 @BeforeEach setUp()57 public void setUp() { 58 iString = "foo"; 59 iInteger = Integer.valueOf(7); 60 iMap = new HashMap<>(); 61 iMap.put("FOO", iString); 62 iMap.put("BAR", iInteger); 63 } 64 65 66 @Test testConstructor()67 public void testConstructor() { 68 assertNotNull(new SerializationUtils()); 69 final Constructor<?>[] cons = SerializationUtils.class.getDeclaredConstructors(); 70 assertEquals(1, cons.length); 71 assertTrue(Modifier.isPublic(cons[0].getModifiers())); 72 assertTrue(Modifier.isPublic(SerializationUtils.class.getModifiers())); 73 assertFalse(Modifier.isFinal(SerializationUtils.class.getModifiers())); 74 } 75 76 @Test testException()77 public void testException() { 78 SerializationException serEx; 79 final Exception ex = new Exception(); 80 81 serEx = new SerializationException(); 82 assertSame(null, serEx.getMessage()); 83 assertSame(null, serEx.getCause()); 84 85 serEx = new SerializationException("Message"); 86 assertSame("Message", serEx.getMessage()); 87 assertSame(null, serEx.getCause()); 88 89 serEx = new SerializationException(ex); 90 assertEquals("java.lang.Exception", serEx.getMessage()); 91 assertSame(ex, serEx.getCause()); 92 93 serEx = new SerializationException("Message", ex); 94 assertSame("Message", serEx.getMessage()); 95 assertSame(ex, serEx.getCause()); 96 } 97 98 99 @Test testSerializeStream()100 public void testSerializeStream() throws Exception { 101 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream(); 102 SerializationUtils.serialize(iMap, streamTest); 103 104 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 105 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 106 oos.writeObject(iMap); 107 oos.flush(); 108 } 109 110 final byte[] testBytes = streamTest.toByteArray(); 111 final byte[] realBytes = streamReal.toByteArray(); 112 assertEquals(testBytes.length, realBytes.length); 113 assertArrayEquals(realBytes, testBytes); 114 } 115 116 @Test testSerializeStreamUnserializable()117 public void testSerializeStreamUnserializable() { 118 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream(); 119 iMap.put(new Object(), new Object()); 120 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap, streamTest)); 121 } 122 123 @Test testSerializeStreamNullObj()124 public void testSerializeStreamNullObj() throws Exception { 125 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream(); 126 SerializationUtils.serialize(null, streamTest); 127 128 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 129 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 130 oos.writeObject(null); 131 oos.flush(); 132 } 133 134 final byte[] testBytes = streamTest.toByteArray(); 135 final byte[] realBytes = streamReal.toByteArray(); 136 assertEquals(testBytes.length, realBytes.length); 137 assertArrayEquals(realBytes, testBytes); 138 } 139 140 @Test testSerializeStreamObjNull()141 public void testSerializeStreamObjNull() { 142 assertThrows(NullPointerException.class, () -> SerializationUtils.serialize(iMap, null)); 143 } 144 145 @Test testSerializeStreamNullNull()146 public void testSerializeStreamNullNull() { 147 assertThrows(NullPointerException.class, () -> SerializationUtils.serialize(null, null)); 148 } 149 150 @Test testSerializeIOException()151 public void testSerializeIOException() { 152 // forces an IOException when the ObjectOutputStream is created, to test not closing the stream 153 // in the finally block 154 final OutputStream streamTest = new OutputStream() { 155 @Override 156 public void write(final int arg0) throws IOException { 157 throw new IOException(SERIALIZE_IO_EXCEPTION_MESSAGE); 158 } 159 }; 160 final SerializationException e = 161 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap, streamTest)); 162 assertEquals("java.io.IOException: " + SERIALIZE_IO_EXCEPTION_MESSAGE, e.getMessage()); 163 } 164 165 166 @Test testDeserializeStream()167 public void testDeserializeStream() throws Exception { 168 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 169 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 170 oos.writeObject(iMap); 171 oos.flush(); 172 } 173 174 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray()); 175 final Object test = SerializationUtils.deserialize(inTest); 176 assertNotNull(test); 177 assertTrue(test instanceof HashMap<?, ?>); 178 assertNotSame(test, iMap); 179 final HashMap<?, ?> testMap = (HashMap<?, ?>) test; 180 assertEquals(iString, testMap.get("FOO")); 181 assertNotSame(iString, testMap.get("FOO")); 182 assertEquals(iInteger, testMap.get("BAR")); 183 assertNotSame(iInteger, testMap.get("BAR")); 184 assertEquals(iMap, testMap); 185 } 186 187 @Test testDeserializeClassCastException()188 public void testDeserializeClassCastException() { 189 final String value = "Hello"; 190 final byte[] serialized = SerializationUtils.serialize(value); 191 assertEquals(value, SerializationUtils.deserialize(serialized)); 192 assertThrows(ClassCastException.class, () -> { 193 // Causes ClassCastException in call site, not in SerializationUtils.deserialize 194 @SuppressWarnings("unused") // needed to cause Exception 195 final Integer i = SerializationUtils.deserialize(serialized); 196 }); 197 } 198 199 @Test testDeserializeStreamOfNull()200 public void testDeserializeStreamOfNull() throws Exception { 201 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 202 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 203 oos.writeObject(null); 204 oos.flush(); 205 } 206 207 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray()); 208 final Object test = SerializationUtils.deserialize(inTest); 209 assertNull(test); 210 } 211 212 @Test testDeserializeStreamNull()213 public void testDeserializeStreamNull() { 214 assertThrows(NullPointerException.class, () -> SerializationUtils.deserialize((InputStream) null)); 215 } 216 217 @Test testDeserializeStreamBadStream()218 public void testDeserializeStreamBadStream() { 219 assertThrows(SerializationException.class, 220 () -> SerializationUtils.deserialize(new ByteArrayInputStream(new byte[0]))); 221 } 222 223 @Test testDeserializeStreamClassNotFound()224 public void testDeserializeStreamClassNotFound() throws Exception { 225 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 226 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 227 oos.writeObject(new ClassNotFoundSerialization()); 228 oos.flush(); 229 } 230 231 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray()); 232 final SerializationException se = assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(inTest)); 233 assertEquals("java.lang.ClassNotFoundException: " + CLASS_NOT_FOUND_MESSAGE, se.getMessage()); 234 } 235 236 @Test testRoundtrip()237 public void testRoundtrip() { 238 final HashMap<Object, Object> newMap = SerializationUtils.roundtrip(iMap); 239 assertEquals(iMap, newMap); 240 } 241 242 @Test testSerializeBytes()243 public void testSerializeBytes() throws Exception { 244 final byte[] testBytes = SerializationUtils.serialize(iMap); 245 246 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 247 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 248 oos.writeObject(iMap); 249 oos.flush(); 250 } 251 252 final byte[] realBytes = streamReal.toByteArray(); 253 assertEquals(testBytes.length, realBytes.length); 254 assertArrayEquals(realBytes, testBytes); 255 } 256 257 @Test testSerializeBytesUnserializable()258 public void testSerializeBytesUnserializable() { 259 iMap.put(new Object(), new Object()); 260 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap)); 261 } 262 263 @Test testSerializeBytesNull()264 public void testSerializeBytesNull() throws Exception { 265 final byte[] testBytes = SerializationUtils.serialize(null); 266 267 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 268 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 269 oos.writeObject(null); 270 oos.flush(); 271 } 272 273 final byte[] realBytes = streamReal.toByteArray(); 274 assertEquals(testBytes.length, realBytes.length); 275 assertArrayEquals(realBytes, testBytes); 276 } 277 278 279 @Test testDeserializeBytes()280 public void testDeserializeBytes() throws Exception { 281 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 282 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 283 oos.writeObject(iMap); 284 oos.flush(); 285 } 286 287 final Object test = SerializationUtils.deserialize(streamReal.toByteArray()); 288 assertNotNull(test); 289 assertTrue(test instanceof HashMap<?, ?>); 290 assertNotSame(test, iMap); 291 final HashMap<?, ?> testMap = (HashMap<?, ?>) test; 292 assertEquals(iString, testMap.get("FOO")); 293 assertNotSame(iString, testMap.get("FOO")); 294 assertEquals(iInteger, testMap.get("BAR")); 295 assertNotSame(iInteger, testMap.get("BAR")); 296 assertEquals(iMap, testMap); 297 } 298 299 @Test testDeserializeBytesOfNull()300 public void testDeserializeBytesOfNull() throws Exception { 301 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream(); 302 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) { 303 oos.writeObject(null); 304 oos.flush(); 305 } 306 307 final Object test = SerializationUtils.deserialize(streamReal.toByteArray()); 308 assertNull(test); 309 } 310 311 @Test testDeserializeBytesNull()312 public void testDeserializeBytesNull() { 313 assertThrows(NullPointerException.class, () -> SerializationUtils.deserialize((byte[]) null)); 314 } 315 316 @Test testDeserializeBytesBadStream()317 public void testDeserializeBytesBadStream() { 318 assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(new byte[0])); 319 } 320 321 322 @Test testClone()323 public void testClone() { 324 final Object test = SerializationUtils.clone(iMap); 325 assertNotNull(test); 326 assertTrue(test instanceof HashMap<?, ?>); 327 assertNotSame(test, iMap); 328 final HashMap<?, ?> testMap = (HashMap<?, ?>) test; 329 assertEquals(iString, testMap.get("FOO")); 330 assertNotSame(iString, testMap.get("FOO")); 331 assertEquals(iInteger, testMap.get("BAR")); 332 assertNotSame(iInteger, testMap.get("BAR")); 333 assertEquals(iMap, testMap); 334 } 335 336 @Test testCloneNull()337 public void testCloneNull() { 338 final Object test = SerializationUtils.clone(null); 339 assertNull(test); 340 } 341 342 @Test testCloneUnserializable()343 public void testCloneUnserializable() { 344 iMap.put(new Object(), new Object()); 345 assertThrows(SerializationException.class, () -> SerializationUtils.clone(iMap)); 346 } 347 348 @Test testPrimitiveTypeClassSerialization()349 public void testPrimitiveTypeClassSerialization() { 350 final Class<?>[] primitiveTypes = { byte.class, short.class, int.class, long.class, float.class, double.class, 351 boolean.class, char.class, void.class }; 352 353 for (final Class<?> primitiveType : primitiveTypes) { 354 final Class<?> clone = SerializationUtils.clone(primitiveType); 355 assertEquals(primitiveType, clone); 356 } 357 } 358 359 } 360 361 class ClassNotFoundSerialization implements Serializable { 362 363 private static final long serialVersionUID = 1L; 364 readObject(final ObjectInputStream in)365 private void readObject(final ObjectInputStream in) throws ClassNotFoundException { 366 throw new ClassNotFoundException(SerializationUtilsTest.CLASS_NOT_FOUND_MESSAGE); 367 } 368 } 369