File: BundleDeserializationCast.md

package info (click to toggle)
error-prone-java 2.18.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 23,204 kB
  • sloc: java: 222,992; xml: 1,319; sh: 25; makefile: 7
file content (81 lines) | stat: -rw-r--r-- 3,260 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
When a `Serializable` object is placed in an `android.os.Bundle`, certain types
whose serialization is handled with custom logic are 'flattened' to their base
types. Casting items retrieved from a bundle with `bundle.getSerializable(...)`
back to their original types may therefore cause a `ClassCastException`.

See [discussion here](https://code.google.com/p/android/issues/detail?id=3847).

Casting the result of `bundle.getSerializable(...)` to any subtype of any of the
following classes is forbidden[^1]:

*   `Map` (except `HashMap`)
*   `List` (except `ArrayList` or any `Parcelable`)
*   `SparseArray` (except `Parcelable`s)
*   `CharSequence` (except `String` or any `Parcelable`)
*   `CharSequence[]` (except `String[]`)

Note that `getSerializable` happens to return `HashMap`s for any `Map`
implementation or `ArrayList`s for any `List` implementation, however, this is
not guaranteed by the API. Therefore, casting to `ArrayList` or `HashMap` is
allowed, but it is safer to cast to the base `List` or `Map`.

An exception is made for most types if they also implement `Parcelable`, as they
are handled such that their type is preserved.

In many cases, you may be able to cast your object to its base type without any
ill effects if you don't require any features of a specific implementation.

In other cases, there may be an constructor that will create an instance of your
type from an instance of the base type (but beware of null results causing
IllegalArgumentExceptions!) For example:

```java
TreeMap<K, V> myMap;
Map<K, V> deserialized = (Map<K, V>) myBundle.getSerializable("KEY");
myMap = deserialized == null ? null : new TreeMap<K, V>(deserialized);
```

If you really need a different workaround, wrapping your object (e.g. of type
`MyList`) in an arbitrary wrapper class (e.g. `MyListHolder`) that implements
just `Serializable` will serialize and deserialize it through the standard
`Serializable` path and preserve your original type.

[^1]: Here is a full list of types that are handled specially in the
    bundling/parceling serialization/deserialization process, in order of
    precedence. If a serialized object inherits from multiple types on this
    list, it will be bundled as the first of those types to appear. e.g. if an
    object implements both Parcelable and List, it will be serialized as a
    Parcelable rather than a List, and its type will be preserved. Note also
    that it is okay to cast to `String` even though it inherits from
    `CharSequence` since `String` is handled first.

    *   `String`
    *   `Integer`
    *   `Map`
    *   `Bundle`
    *   `PersistableBundle`
    *   `Parcelable` - Parcelables are handled such that their type is
        preserved.
    *   `Short`
    *   `Long`
    *   `Float`
    *   `Double`
    *   `Boolean`
    *   `CharSequence`
    *   `List`
    *   `SparseArray`
    *   `boolean[]`
    *   `byte[]`
    *   `String[]`
    *   `CharSequence[]`
    *   `IBinder`
    *   `Parcelable[]`
    *   `int[]`
    *   `long[]`
    *   `Byte`
    *   `Size`
    *   `SizeF`
    *   `double[]`
    *   `Object[]` - Only handles pure Object[], not subtypes.
    *   All other `Serializable` objects go through the normal serialization
        path, types are preserved.