97c17d523838299fb01201d2b192101614ea149c
[so.git] / bpmn / so-bpmn-building-blocks / src / test / java / org / onap / so / SerializableChecker.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 - 2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.so;
22
23 import java.io.Serializable;
24 import java.lang.reflect.Field;
25 import java.lang.reflect.Modifier;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Set;
31
32 public final class SerializableChecker
33 {
34     public static class SerializationFailure
35     {
36         private final String mContainingClass;
37         private final String mMemberName;
38
39         public SerializationFailure(String inNonSerializableClass, String inMemberName)
40         {
41             mContainingClass = inNonSerializableClass;
42             mMemberName = inMemberName;
43         }
44
45         public String getContainingClass()
46         {
47             return mContainingClass;
48         }
49
50         public String getMemberName()
51         {
52             return mMemberName;
53         }
54
55         public String getBadMemberString()
56         {
57             if (mMemberName == null)
58                 return mContainingClass;
59             return mContainingClass + "." + mMemberName;
60         }
61
62         @Override
63         public String toString()
64         {
65             return "SerializationFailure [mNonSerializableClass=" + mContainingClass + ", mMemberName=" + mMemberName + "]";
66         }
67     }
68
69     private static class SerializationCheckerData
70     {
71         private Set<Class<?>> mSerializableClasses;
72
73         SerializationCheckerData()
74         {
75             mSerializableClasses = new HashSet<Class<?>>();
76         }
77
78         boolean isAlreadyChecked(Class<?> inClass)
79         {
80             return mSerializableClasses.contains(inClass);
81         }
82
83         void addSerializableClass(Class<?> inClass)
84         {
85             mSerializableClasses.add(inClass);
86         }
87     }
88
89     private SerializableChecker()
90     { }
91
92     public static SerializationFailure isFullySerializable(Class<?> inClass)
93     {
94         if (!isSerializable(inClass))
95             return new SerializationFailure(inClass.getName(), null);
96
97         return isFullySerializable(inClass, new SerializationCheckerData());
98     }
99
100     private static SerializationFailure isFullySerializable(Class<?> inClass, SerializationCheckerData inSerializationCheckerData)
101     {
102         for (Field field : declaredFields(inClass))
103         {
104             Class<?> fieldDeclaringClass = field.getType();
105
106             if (field.getType() == Object.class)
107                 continue;
108
109             if (Modifier.isStatic(field.getModifiers()))
110                 continue;
111
112             if (field.isSynthetic())
113                 continue;
114
115             if (fieldDeclaringClass.isInterface() || fieldDeclaringClass.isPrimitive())
116                 continue;
117
118             if (Modifier.isAbstract(field.getType().getModifiers()))
119                 continue;
120
121             if (inSerializationCheckerData.isAlreadyChecked(fieldDeclaringClass))
122                 continue;
123
124             if (isSerializable(fieldDeclaringClass))
125             {
126                 inSerializationCheckerData.addSerializableClass(inClass);
127
128                 SerializationFailure failure = isFullySerializable(field.getType(), inSerializationCheckerData);
129                 if (failure != null)
130                     return failure;
131                 else
132                     continue;
133             }
134
135             if (Modifier.isTransient(field.getModifiers()))
136                 continue;
137
138             return new SerializationFailure(field.getDeclaringClass().getName(), field.getName());
139         }
140         return null;
141     }
142
143     private static boolean isSerializable(Class<?> inClass)
144     {
145         Set<Class<?>> interfaces = getInterfaces(inClass);
146         if (interfaces == null)
147             return false;
148         boolean isSerializable = interfaces.contains(Serializable.class);
149         if (isSerializable)
150             return true;
151
152         for (Class<?> classInterface : interfaces)
153         {
154             if (isSerializable(classInterface))
155                 return true;
156         }
157
158         if (inClass.getSuperclass() != null && isSerializable(inClass.getSuperclass()))
159             return true;
160
161         return false;
162     }
163
164     private static Set<Class<?>> getInterfaces(Class<?> inFieldDeclaringClass)
165     {
166         return new HashSet<Class<?>>(Arrays.asList(inFieldDeclaringClass.getInterfaces()));
167     }
168
169     private static List<Field> declaredFields(Class<?> inClass)
170     {
171         List<Field> fields = new ArrayList<Field>(Arrays.asList(inClass.getDeclaredFields()));
172
173         Class<?> parentClasses = inClass.getSuperclass();
174
175         if (parentClasses == null)
176             return fields;
177         fields.addAll(declaredFields(parentClasses));
178
179         return fields;
180         }
181     }