Switch on java.lang.Class
Brian Goetz
brian.goetz at oracle.com
Mon Apr 9 13:38:15 UTC 2018
I'm skeptical of this feature, because (a) its not as widely applicable
as it looks, (b) its error-prone.
Both of these stem from the fact that comparing classes with == excludes
subtypes. So it really only works with final classes -- but if we had a
feature like this, people might mistakenly use it with nonfinal classes,
and be surprised when a subtype shows up (this can happen even when your
IDE tells you there are no subtypes, because of dynamic proxies). And
all of the examples you show are in low-level libraries, which is a
warning sign.
Where did these snippets get their Class from? Good chance, case 1 got
it from calling Object.getClass(). In which case, they can just pattern
match on the type of the thing:
switch (date) {
case Date d: ...
case Timestamp t: ...
default: ...
}
Case 2 is more likely just operating on types that it got from a
reflection API. If you have only a few entries, an if-else will do; if
you have more entries, a Map is likely to be the better choice. For
situations like this, I'd rather invest in map literals or better
Map.of() builders.
So, I would worry this feature is unlikely to carry its weight, and
further, may lead to misuse.
On 4/9/2018 1:07 AM, Tagir Valeev wrote:
> Hello!
>
> I don't remember whether switch on java.lang.Class instance was
> discussed. I guess, this pattern is quite common and it will be useful
> to support it. Such code often appears in deserialization logic when
> we branch on desired type to deserialize. Here are a couple of
> examples from opensource libraries:
>
> 1. com.google.gson.DefaultDateTypeAdapter#read (gson-2.8.2):
>
> Date date = deserializeToDate(in.nextString());
> if (dateType == Date.class) {
> return date;
> } else if (dateType == Timestamp.class) {
> return new Timestamp(date.getTime());
> } else if (dateType == java.sql.Date.class) {
> return new java.sql.Date(date.getTime());
> } else {
> // This must never happen: dateType is guarded in the primary
> constructor
> throw new AssertionError();
> }
>
> Could be rewritten as:
>
> Date date = deserializeToDate(in.nextString());
> return switch(dateType) {
> case Date.class -> date;
> case Timestamp.class -> new Timestamp(date.getTime());
> case java.sql.Date.class -> new java.sql.Date(date.getTime());
> default ->
> // This must never happen: dateType is guarded in the primary
> constructor
> throw new AssertionError();
> };
>
> 2.
> com.fasterxml.jackson.databind.deser.std.FromStringDeserializer#findDeserializer
> (jackson-databind-2.9.4):
>
> public static Std findDeserializer(Class<?> rawType)
> {
> int kind = 0;
> if (rawType == File.class) {
> kind = Std.STD_FILE;
> } else if (rawType == URL.class) {
> kind = Std.STD_URL;
> } else if (rawType == URI.class) {
> kind = Std.STD_URI;
> } else if (rawType == Class.class) {
> kind = Std.STD_CLASS;
> } else if (rawType == JavaType.class) {
> kind = Std.STD_JAVA_TYPE;
> } else if // more branches like this
> } else {
> return null;
> }
> return new Std(rawType, kind);
> }
>
> Could be rewritten as:
>
> public static Std findDeserializer(Class<?> rawType)
> {
> int kind = switch(rawType) {
> case File.class -> Std.STD_FILE;
> case URL.class -> Std.STD_URL;
> case URI.class -> Std.STD_URI;
> case Class.cass -> Std.STD_CLASS;
> case JavaType.class -> Std.STD_JAVA_TYPE;
> ...
> default -> 0;
> };
> return kind == 0 ? null : new Std(rawType, kind);
> }
>
> In such code all branches are mutually exclusive. The bootstrap method
> can generate a lookupswitch based on Class.hashCode, then equals
> checks, pretty similar to String switch implementation. Unlike String
> hash codes Class.hashCode is not stable and varies between JVM
> launches, but they are already known during the bootstrap and we can
> trust them during the VM lifetime, so we can generate a lookupswitch.
> The minor problematic point is to support primitive classes like
> int.class. This cannot be passed directly as indy static argument, but
> this can be solved with condy.
>
> What do you think?
>
> With best regards,
> Tagir Valeev.
>
More information about the amber-spec-experts
mailing list