View Javadoc
1   package org.djunits;
2   
3   import static org.junit.jupiter.api.Assertions.fail;
4   
5   import java.io.File;
6   import java.io.IOException;
7   import java.io.Serializable;
8   import java.lang.reflect.Constructor;
9   import java.lang.reflect.Modifier;
10  import java.net.URISyntaxException;
11  import java.nio.charset.StandardCharsets;
12  import java.nio.file.Files;
13  import java.nio.file.Paths;
14  import java.util.ArrayList;
15  import java.util.Arrays;
16  import java.util.List;
17  
18  /**
19   * SerializableTest.java. <br>
20   * <p>
21   * Copyright (c) 2003-2024 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved.<br>
22   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
23   * </p>
24   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
25   */
26  public class SerializableTest
27  {
28      /**
29       * Test whether non-utility classes are serializable.
30       * @throws URISyntaxException on I/O error
31       * @throws IOException on I/O error
32       * @throws ClassNotFoundException when class could not be resolved
33       */
34      // FIXME: @Test
35      public void serializableTest() throws URISyntaxException, IOException, ClassNotFoundException
36      {
37          File classFolder = new File(SerializableTest.class.getResource("/").toURI());
38          File projectFolder = classFolder.getParentFile().getParentFile();
39          if (projectFolder.isDirectory() && projectFolder.getName().equals("djunits")
40                  && new File(projectFolder, "src/main/java").exists())
41          {
42              File sourcePathFile = new File(projectFolder, "src/main/java");
43              for (File srcFolder : sourcePathFile.listFiles())
44              {
45                  processDirOrFile(srcFolder);
46              }
47          }
48      }
49  
50      /**
51       * @param srcFolder File; folder to look for subfolders and/or java files
52       * @throws IOException on i/o error
53       * @throws ClassNotFoundException on error
54       */
55      private void processDirOrFile(final File srcFolder) throws IOException, ClassNotFoundException
56      {
57          if (srcFolder.isDirectory())
58          {
59              for (File subFile : srcFolder.listFiles())
60              {
61                  if (subFile.isDirectory())
62                  {
63                      processDirOrFile(subFile);
64                  }
65                  else if (subFile.getName().endsWith(".java") && !subFile.getName().startsWith("package-info"))
66                  {
67                      processJavaFile(subFile);
68                  }
69              }
70          }
71      }
72  
73      /**
74       * @param javaFile File; java file to process
75       * @throws IOException on error
76       * @throws ClassNotFoundException on error
77       */
78      private void processJavaFile(final File javaFile) throws IOException, ClassNotFoundException
79      {
80          // system.out.println("Test Serializable in " + javaFile.toURI().getPath());
81          List<String> lines = Files.readAllLines(Paths.get(javaFile.toURI()), StandardCharsets.UTF_8);
82  
83          // find the package
84          String pack = null;
85          for (String line : lines)
86          {
87              if (line.trim().startsWith("package "))
88              {
89                  pack = line.trim().substring(8, line.trim().length() - 1);
90                  break;
91              }
92          }
93          if (pack == null)
94          {
95              fail("Could not find package in Java file " + javaFile.toURI().getPath());
96          }
97  
98          // find the class (TODO: how to deal with subclasses)
99          String className = pack + "." + javaFile.getName();
100         className = className.replaceAll("\\.java", "");
101         Class<?> clazz = Class.forName(className);
102 
103         if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers()))
104         {
105             // is there a public constructor? (non-utility class)
106             List<Constructor<?>> constructors = new ArrayList<>();
107             constructors.addAll(Arrays.asList(clazz.getDeclaredConstructors()));
108             boolean utilityClass = true;
109             for (Constructor<?> constructor : constructors)
110             {
111                 if (Modifier.isPublic(constructor.getModifiers()) || Modifier.isProtected(constructor.getModifiers()))
112                 {
113                     utilityClass = false;
114                     break;
115                 }
116             }
117 
118             if (!utilityClass)
119             {
120                 // system.out.println(" -- Testing class " + className);
121 
122                 // is the class Serializable?
123                 if (!Serializable.class.isAssignableFrom(clazz))
124                 {
125                     fail("NOT SERIALIZABLE: class " + className);
126                 }
127             }
128         }
129     }
130 }