The SonarQube rule squid:S1948 requires that all fields of a serializable class are either serializable or transient. Another rule states to rather use the interface than the implementation types.
When I have a
public class myClass implements Serializable
{
List<String> names;
...
}
then names
should rather be a List<String>
than e.g. ArrayList<String>
. But then rule S1948 tells us that List
isn't serializable.
Solution at a first glance: define an interface SerializableList
- maybe like this:
public interface SerializableList<E> extends List<E>, Serializable
{
}
If we declare names
to be a
SerializableList<String> names;
the warning from rule S1948 is gone, but an assignment names = new ArrayList<String>();
results in a Type mismatch: cannot convert from ArrayList<String> to SerializableList<String>
.
Two questions:
List<String> names = new ArrayList<String>();
without a warning nor need to cast, but cannot declare SerializableList<String> names = new ArrayList<String>();
? I wonder, because ArrayList<E> implements List<E>, Serializable, ...
- why isn't it a SerializableList
?names
in a way that neither S1948 nor the other rule will give a warning, but I can still be free to use any kind of List
that is also Serializable
(like ArrayList
, ...) and without need for an explicit cast.Thanks for any hints.
why can I declare
List<String> names = new ArrayList<String>();
without a warning nor need to cast, but cannot declareSerializableList<String> names = new ArrayList<String>();
? I wonder, becauseArrayList<E> implements List<E>, Serializable, ...
- why isn't it aSerializableList
?
You want to use a structure/feature which does not exist in Java ("a grouping interface"). Right now you introduced a new type SerializableList
which extends other types:
List Serializable
↑ ↑
SerializableList
ArrayList
also extends both parent types of the SerializableList
:
List Serializable
↑ ↑
ArrayList
but they are no connection between SerializableList
and ArrayList
. If we define a new type:
public class SerializableListImpl extends ArrayList implements SerializableList
then we have:
--------→ List ←---------
| |
| --→ Serializable ←-- |
| | | |
ArrayList SerializableList
↑ ↑
SerializableListImpl
and finally:
List serializableList = new SerializableListImpl();
System.out.println(serializableList instanceof List); // true
System.out.println(serializableList instanceof Serializable); // true
System.out.println(serializableList instanceof ArrayList); // true
System.out.println(serializableList instanceof SerializableList); // true
List arrayList = new ArrayList();
System.out.println(arrayList instanceof List); // true
System.out.println(arrayList instanceof Serializable); // true
System.out.println(arrayList instanceof ArrayList); // true
System.out.println(arrayList instanceof SerializableList); // false ← not in the hierarchy
how to declare names in a way that neither S1948 nor the other rule will give a warning, but I can still be free to use any kind of
List
that is alsoSerializable
(likeArrayList
, ...) and without need for an explicit cast.
You cannot. Not every implementation of the List
interface have to be also Serializable
. Anyone can define a new type:
public class MyList implements List {
...
}
assign to the names
field and then:
List myList = new MyList();
System.out.println(serializableList instanceof List); // true
System.out.println(serializableList instanceof Serializable); // false ← not in the hierarchy
As I wrote at the top such feature as "a grouping interface":
SerializableList == List<String>&&Serializable
does not exist so you have to mark the issue as Won't Fix
.