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 {
33 public static class SerializationFailure {
34 private final String mContainingClass;
35 private final String mMemberName;
37 public SerializationFailure(String inNonSerializableClass, String inMemberName) {
38 mContainingClass = inNonSerializableClass;
39 mMemberName = inMemberName;
42 public String getContainingClass() {
43 return mContainingClass;
46 public String getMemberName() {
50 public String getBadMemberString() {
51 if (mMemberName == null)
52 return mContainingClass;
53 return mContainingClass + "." + mMemberName;
57 public String toString() {
58 return "SerializationFailure [mNonSerializableClass=" + mContainingClass + ", mMemberName=" + mMemberName
63 private static class SerializationCheckerData {
64 private Set<Class<?>> mSerializableClasses;
66 SerializationCheckerData() {
67 mSerializableClasses = new HashSet<Class<?>>();
70 boolean isAlreadyChecked(Class<?> inClass) {
71 return mSerializableClasses.contains(inClass);
74 void addSerializableClass(Class<?> inClass) {
75 mSerializableClasses.add(inClass);
79 private SerializableChecker() {}
81 public static SerializationFailure isFullySerializable(Class<?> inClass) {
82 if (!isSerializable(inClass))
83 return new SerializationFailure(inClass.getName(), null);
85 return isFullySerializable(inClass, new SerializationCheckerData());
88 private static SerializationFailure isFullySerializable(Class<?> inClass,
89 SerializationCheckerData inSerializationCheckerData) {
90 for (Field field : declaredFields(inClass)) {
91 Class<?> fieldDeclaringClass = field.getType();
93 if (field.getType() == Object.class)
96 if (Modifier.isStatic(field.getModifiers()))
99 if (field.isSynthetic())
102 if (fieldDeclaringClass.isInterface() || fieldDeclaringClass.isPrimitive())
105 if (Modifier.isAbstract(field.getType().getModifiers()))
108 if (inSerializationCheckerData.isAlreadyChecked(fieldDeclaringClass))
111 if (isSerializable(fieldDeclaringClass)) {
112 inSerializationCheckerData.addSerializableClass(inClass);
114 SerializationFailure failure = isFullySerializable(field.getType(), inSerializationCheckerData);
121 if (Modifier.isTransient(field.getModifiers()))
124 return new SerializationFailure(field.getDeclaringClass().getName(), field.getName());
129 private static boolean isSerializable(Class<?> inClass) {
130 Set<Class<?>> interfaces = getInterfaces(inClass);
131 if (interfaces == null)
133 boolean isSerializable = interfaces.contains(Serializable.class);
137 for (Class<?> classInterface : interfaces) {
138 if (isSerializable(classInterface))
142 if (inClass.getSuperclass() != null && isSerializable(inClass.getSuperclass()))
148 private static Set<Class<?>> getInterfaces(Class<?> inFieldDeclaringClass) {
149 return new HashSet<Class<?>>(Arrays.asList(inFieldDeclaringClass.getInterfaces()));
152 private static List<Field> declaredFields(Class<?> inClass) {
153 List<Field> fields = new ArrayList<Field>(Arrays.asList(inClass.getDeclaredFields()));
155 Class<?> parentClasses = inClass.getSuperclass();
157 if (parentClasses == null)
159 fields.addAll(declaredFields(parentClasses));