2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
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;
32 public final class SerializableChecker
34 public static class SerializationFailure
36 private final String mContainingClass;
37 private final String mMemberName;
39 public SerializationFailure(String inNonSerializableClass, String inMemberName)
41 mContainingClass = inNonSerializableClass;
42 mMemberName = inMemberName;
45 public String getContainingClass()
47 return mContainingClass;
50 public String getMemberName()
55 public String getBadMemberString()
57 if (mMemberName == null)
58 return mContainingClass;
59 return mContainingClass + "." + mMemberName;
63 public String toString()
65 return "SerializationFailure [mNonSerializableClass=" + mContainingClass + ", mMemberName=" + mMemberName + "]";
69 private static class SerializationCheckerData
71 private Set<Class<?>> mSerializableClasses;
73 SerializationCheckerData()
75 mSerializableClasses = new HashSet<Class<?>>();
78 boolean isAlreadyChecked(Class<?> inClass)
80 return mSerializableClasses.contains(inClass);
83 void addSerializableClass(Class<?> inClass)
85 mSerializableClasses.add(inClass);
89 private SerializableChecker()
92 public static SerializationFailure isFullySerializable(Class<?> inClass)
94 if (!isSerializable(inClass))
95 return new SerializationFailure(inClass.getName(), null);
97 return isFullySerializable(inClass, new SerializationCheckerData());
100 private static SerializationFailure isFullySerializable(Class<?> inClass, SerializationCheckerData inSerializationCheckerData)
102 for (Field field : declaredFields(inClass))
104 Class<?> fieldDeclaringClass = field.getType();
106 if (field.getType() == Object.class)
109 if (Modifier.isStatic(field.getModifiers()))
112 if (field.isSynthetic())
115 if (fieldDeclaringClass.isInterface() || fieldDeclaringClass.isPrimitive())
118 if (Modifier.isAbstract(field.getType().getModifiers()))
121 if (inSerializationCheckerData.isAlreadyChecked(fieldDeclaringClass))
124 if (isSerializable(fieldDeclaringClass))
126 inSerializationCheckerData.addSerializableClass(inClass);
128 SerializationFailure failure = isFullySerializable(field.getType(), inSerializationCheckerData);
135 if (Modifier.isTransient(field.getModifiers()))
138 return new SerializationFailure(field.getDeclaringClass().getName(), field.getName());
143 private static boolean isSerializable(Class<?> inClass)
145 Set<Class<?>> interfaces = getInterfaces(inClass);
146 if (interfaces == null)
148 boolean isSerializable = interfaces.contains(Serializable.class);
152 for (Class<?> classInterface : interfaces)
154 if (isSerializable(classInterface))
158 if (inClass.getSuperclass() != null && isSerializable(inClass.getSuperclass()))
164 private static Set<Class<?>> getInterfaces(Class<?> inFieldDeclaringClass)
166 return new HashSet<Class<?>>(Arrays.asList(inFieldDeclaringClass.getInterfaces()));
169 private static List<Field> declaredFields(Class<?> inClass)
171 List<Field> fields = new ArrayList<Field>(Arrays.asList(inClass.getDeclaredFields()));
173 Class<?> parentClasses = inClass.getSuperclass();
175 if (parentClasses == null)
177 fields.addAll(declaredFields(parentClasses));