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