1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3;
18
19 import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
20 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
21 import static org.junit.jupiter.api.Assertions.assertEquals;
22 import static org.junit.jupiter.api.Assertions.assertFalse;
23 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertNotSame;
26 import static org.junit.jupiter.api.Assertions.assertNull;
27 import static org.junit.jupiter.api.Assertions.assertSame;
28 import static org.junit.jupiter.api.Assertions.assertThrows;
29 import static org.junit.jupiter.api.Assertions.assertTrue;
30 import static org.junit.jupiter.api.Assertions.fail;
31
32 import java.io.ByteArrayInputStream;
33 import java.io.ByteArrayOutputStream;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.ObjectInputStream;
37 import java.io.ObjectOutputStream;
38 import java.io.OutputStream;
39 import java.io.Serializable;
40 import java.lang.reflect.Constructor;
41 import java.lang.reflect.Modifier;
42 import java.util.HashMap;
43 import java.util.function.Supplier;
44
45 import org.junit.jupiter.api.BeforeEach;
46 import org.junit.jupiter.api.Test;
47
48 final class ClassNotFoundSerialization implements Serializable {
49
50 private static final long serialVersionUID = 1L;
51
52 private void readObject(final ObjectInputStream in) throws ClassNotFoundException {
53 throw new ClassNotFoundException(SerializationUtilsTest.CLASS_NOT_FOUND_MESSAGE);
54 }
55 }
56
57 interface SerializableSupplier<T> extends Supplier<T>, Serializable {
58
59 }
60
61
62
63
64 public class SerializationUtilsTest extends AbstractLangTest {
65
66 static final String CLASS_NOT_FOUND_MESSAGE = "ClassNotFoundSerialization.readObject fake exception";
67
68 protected static final String SERIALIZE_IO_EXCEPTION_MESSAGE = "Anonymous OutputStream I/O exception";
69
70 public static byte[] intToBytes(final int v) {
71 return new byte[] { (byte) (v >>> 24), (byte) (v >>> 16), (byte) (v >>> 8), (byte) v };
72 }
73
74 public static byte[] replaceLastInt(final byte[] src, final int from, final int to) {
75 final byte[] fromB = intToBytes(from);
76 final byte[] toB = intToBytes(to);
77 final byte[] out = src.clone();
78 for (int i = out.length - 4; i >= 0; i--) {
79 if (out[i] == fromB[0] && out[i + 1] == fromB[1] && out[i + 2] == fromB[2] && out[i + 3] == fromB[3]) {
80 out[i] = toB[0];
81 out[i + 1] = toB[1];
82 out[i + 2] = toB[2];
83 out[i + 3] = toB[3];
84 return out;
85 }
86 }
87 fail("No legitimate int in stream, serialization must keep hashCode in default field set");
88 return null;
89 }
90
91 private String iString;
92
93 private Integer iInteger;
94
95 private HashMap<Object, Object> iMap;
96
97 @BeforeEach
98 public void setUp() {
99 iString = "foo";
100 iInteger = Integer.valueOf(7);
101 iMap = new HashMap<>();
102 iMap.put("FOO", iString);
103 iMap.put("BAR", iInteger);
104 }
105
106 @Test
107 void testClone() {
108 final Object test = SerializationUtils.clone(iMap);
109 assertNotNull(test);
110 assertInstanceOf(HashMap.class, test);
111 assertNotSame(test, iMap);
112 final HashMap<?, ?> testMap = (HashMap<?, ?>) test;
113 assertEquals(iString, testMap.get("FOO"));
114 assertNotSame(iString, testMap.get("FOO"));
115 assertEquals(iInteger, testMap.get("BAR"));
116 assertNotSame(iInteger, testMap.get("BAR"));
117 assertEquals(iMap, testMap);
118 }
119
120 @Test
121 void testCloneNull() {
122 final Object test = SerializationUtils.clone(null);
123 assertNull(test);
124 }
125
126 @Test
127 void testCloneSerializableSupplier() {
128 final SerializableSupplier<String> supplier = () -> "test";
129 assertEquals("test", supplier.get());
130 final SerializableSupplier<String> clone = SerializationUtils.clone(supplier);
131 assertEquals("test", clone.get());
132 }
133
134 @Test
135 void testCloneUnserializable() {
136 iMap.put(new Object(), new Object());
137 assertThrows(SerializationException.class, () -> SerializationUtils.clone(iMap));
138 }
139
140 @SuppressWarnings("deprecation")
141 @Test
142 void testConstructor() {
143 assertNotNull(new SerializationUtils());
144 final Constructor<?>[] cons = SerializationUtils.class.getDeclaredConstructors();
145 assertEquals(1, cons.length);
146 assertTrue(Modifier.isPublic(cons[0].getModifiers()));
147 assertTrue(Modifier.isPublic(SerializationUtils.class.getModifiers()));
148 assertFalse(Modifier.isFinal(SerializationUtils.class.getModifiers()));
149 }
150
151 @Test
152 void testDeserializeBytes() throws Exception {
153 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
154 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
155 oos.writeObject(iMap);
156 oos.flush();
157 }
158
159 final Object test = SerializationUtils.deserialize(streamReal.toByteArray());
160 assertNotNull(test);
161 assertInstanceOf(HashMap.class, test);
162 assertNotSame(test, iMap);
163 final HashMap<?, ?> testMap = (HashMap<?, ?>) test;
164 assertEquals(iString, testMap.get("FOO"));
165 assertNotSame(iString, testMap.get("FOO"));
166 assertEquals(iInteger, testMap.get("BAR"));
167 assertNotSame(iInteger, testMap.get("BAR"));
168 assertEquals(iMap, testMap);
169 }
170
171 @Test
172 void testDeserializeBytesBadStream() {
173 assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(new byte[0]));
174 }
175
176 @Test
177 void testDeserializeBytesNull() {
178 assertNullPointerException(() -> SerializationUtils.deserialize((byte[]) null));
179 }
180
181 @Test
182 void testDeserializeBytesOfNull() throws Exception {
183 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
184 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
185 oos.writeObject(null);
186 oos.flush();
187 }
188
189 final Object test = SerializationUtils.deserialize(streamReal.toByteArray());
190 assertNull(test);
191 }
192
193 @Test
194 void testDeserializeClassCastException() {
195 final String value = "Hello";
196 final byte[] serialized = SerializationUtils.serialize(value);
197 assertEquals(value, SerializationUtils.deserialize(serialized));
198 assertThrows(ClassCastException.class, () -> {
199
200 @SuppressWarnings("unused")
201 final Integer i = SerializationUtils.deserialize(serialized);
202 });
203 }
204
205 @Test
206 void testDeserializeStream() throws Exception {
207 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
208 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
209 oos.writeObject(iMap);
210 oos.flush();
211 }
212
213 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
214 final Object test = SerializationUtils.deserialize(inTest);
215 assertNotNull(test);
216 assertInstanceOf(HashMap.class, test);
217 assertNotSame(test, iMap);
218 final HashMap<?, ?> testMap = (HashMap<?, ?>) test;
219 assertEquals(iString, testMap.get("FOO"));
220 assertNotSame(iString, testMap.get("FOO"));
221 assertEquals(iInteger, testMap.get("BAR"));
222 assertNotSame(iInteger, testMap.get("BAR"));
223 assertEquals(iMap, testMap);
224 }
225
226 @Test
227 void testDeserializeStreamBadStream() {
228 assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(new ByteArrayInputStream(new byte[0])));
229 }
230
231 @Test
232 void testDeserializeStreamClassNotFound() throws Exception {
233 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
234 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
235 oos.writeObject(new ClassNotFoundSerialization());
236 oos.flush();
237 }
238
239 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
240 final SerializationException se = assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(inTest));
241 assertEquals("java.lang.ClassNotFoundException: " + CLASS_NOT_FOUND_MESSAGE, se.getMessage());
242 }
243
244 @Test
245 void testDeserializeStreamNull() {
246 assertNullPointerException(() -> SerializationUtils.deserialize((InputStream) null));
247 }
248
249 @Test
250 void testDeserializeStreamOfNull() throws Exception {
251 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
252 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
253 oos.writeObject(null);
254 oos.flush();
255 }
256
257 final ByteArrayInputStream inTest = new ByteArrayInputStream(streamReal.toByteArray());
258 final Object test = SerializationUtils.deserialize(inTest);
259 assertNull(test);
260 }
261
262 @Test
263 void testException() {
264 SerializationException serEx;
265 final Exception ex = new Exception();
266
267 serEx = new SerializationException();
268 assertSame(null, serEx.getMessage());
269 assertSame(null, serEx.getCause());
270
271 serEx = new SerializationException("Message");
272 assertSame("Message", serEx.getMessage());
273 assertSame(null, serEx.getCause());
274
275 serEx = new SerializationException(ex);
276 assertEquals("java.lang.Exception", serEx.getMessage());
277 assertSame(ex, serEx.getCause());
278
279 serEx = new SerializationException("Message", ex);
280 assertSame("Message", serEx.getMessage());
281 assertSame(ex, serEx.getCause());
282 }
283
284 @Test
285 void testNegativeByteArray() {
286 final byte[] byteArray = {
287 (byte) -84, (byte) -19, (byte) 0, (byte) 5, (byte) 125, (byte) -19, (byte) 0,
288 (byte) 5, (byte) 115, (byte) 114, (byte) -1, (byte) 97, (byte) 122, (byte) -48, (byte) -65
289 };
290
291 assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(new ByteArrayInputStream(byteArray)));
292 }
293
294 @Test
295 void testPrimitiveTypeClassSerialization() {
296 final Class<?>[] primitiveTypes = { byte.class, short.class, int.class, long.class, float.class, double.class,
297 boolean.class, char.class, void.class };
298
299 for (final Class<?> primitiveType : primitiveTypes) {
300 final Class<?> clone = SerializationUtils.clone(primitiveType);
301 assertEquals(primitiveType, clone);
302 }
303 }
304
305 @Test
306 void testRoundtrip() {
307 final HashMap<Object, Object> newMap = SerializationUtils.roundtrip(iMap);
308 assertEquals(iMap, newMap);
309 }
310
311 @Test
312 void testSerializeBytes() throws Exception {
313 final byte[] testBytes = SerializationUtils.serialize(iMap);
314
315 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
316 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
317 oos.writeObject(iMap);
318 oos.flush();
319 }
320
321 final byte[] realBytes = streamReal.toByteArray();
322 assertEquals(testBytes.length, realBytes.length);
323 assertArrayEquals(realBytes, testBytes);
324 }
325
326 @Test
327 void testSerializeBytesNull() throws Exception {
328 final byte[] testBytes = SerializationUtils.serialize(null);
329
330 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
331 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
332 oos.writeObject(null);
333 oos.flush();
334 }
335
336 final byte[] realBytes = streamReal.toByteArray();
337 assertEquals(testBytes.length, realBytes.length);
338 assertArrayEquals(realBytes, testBytes);
339 }
340
341 @Test
342 void testSerializeBytesUnserializable() {
343 iMap.put(new Object(), new Object());
344 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap));
345 }
346
347 @Test
348 void testSerializeIOException() {
349
350
351 final OutputStream streamTest = new OutputStream() {
352 @Override
353 public void write(final int arg0) throws IOException {
354 throw new IOException(SERIALIZE_IO_EXCEPTION_MESSAGE);
355 }
356 };
357 final SerializationException e =
358 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap, streamTest));
359 assertEquals("java.io.IOException: " + SERIALIZE_IO_EXCEPTION_MESSAGE, e.getMessage());
360 }
361
362 @Test
363 void testSerializeStream() throws Exception {
364 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
365 SerializationUtils.serialize(iMap, streamTest);
366
367 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
368 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
369 oos.writeObject(iMap);
370 oos.flush();
371 }
372
373 final byte[] testBytes = streamTest.toByteArray();
374 final byte[] realBytes = streamReal.toByteArray();
375 assertEquals(testBytes.length, realBytes.length);
376 assertArrayEquals(realBytes, testBytes);
377 }
378
379 @Test
380 void testSerializeStreamNullNull() {
381 assertNullPointerException(() -> SerializationUtils.serialize(null, null));
382 }
383
384 @Test
385 void testSerializeStreamNullObj() throws Exception {
386 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
387 SerializationUtils.serialize(null, streamTest);
388
389 final ByteArrayOutputStream streamReal = new ByteArrayOutputStream();
390 try (ObjectOutputStream oos = new ObjectOutputStream(streamReal)) {
391 oos.writeObject(null);
392 oos.flush();
393 }
394
395 final byte[] testBytes = streamTest.toByteArray();
396 final byte[] realBytes = streamReal.toByteArray();
397 assertEquals(testBytes.length, realBytes.length);
398 assertArrayEquals(realBytes, testBytes);
399 }
400
401 @Test
402 void testSerializeStreamObjNull() {
403 assertNullPointerException(() -> SerializationUtils.serialize(iMap, null));
404 }
405
406 @Test
407 void testSerializeStreamUnserializable() {
408 final ByteArrayOutputStream streamTest = new ByteArrayOutputStream();
409 iMap.put(new Object(), new Object());
410 assertThrows(SerializationException.class, () -> SerializationUtils.serialize(iMap, streamTest));
411 }
412 }