I want to write an ArchUnit test to check that all fields in serializable classes are either static, transient, or are Serializable. This means that for all non-primitive types, I have to check if they implement serializable (recursively if these fields are of a non-primitive type).
For collections, I want to check their generics if they are serializable because the serializability of collections depends on this.
So far my rule is laid out like this:
fields().that().areDeclaredInClassesThat().implement(Serializable.class)
.should().beStatic().orShould().haveModifier(JavaModifier.TRANSIENT)
.orShould(new SerializableCondition()).check(classes);
where SerializableCondition implements ArchCondition with the following condition:
private boolean isSerializable(JavaClass javaClass) {
if (javaClass.isPrimitive()) {
return true;
}
// Recursively check if array components are serializable
if (javaClass.isArray()) {
return isSerializable(javaClass.getComponentType());
}
// This check does not work as expected
if (javaClass.isAssignableTo(Collection.class)) {
var x = ((ParameterizedType)
javaClass.reflect().getGenericInterfaces()[0])
.getActualTypeArguments()[0];
return x instanceof Serializable;
}
return javaClass.isAssignableTo(Serializable.class);
}
Obviously, I would like the check for collections to be recursive just like the array one, but right now I want to get it working for simple cases.
To me, it's neither obvious from your question how you use your
isSerializablefrom yourSerializableCondition(probably somehow by evaluating it on the testedJavaField'srawType?), nor what// This check does not work as expectedmeans exactly, but I would try something like this: