0

I try to get a switch case by class working using JDK17 Preview.

    sealed class A permits X,Y{}
    final class X extends A{}
    final class Y extends A{}

    public static <T extends A> List<T> switchByClass(Class<T> clazz) {
        return switch (clazz) {
            case Class<X> x-> xObjects();
            case Class<Y> y-> yObjects();
            default -> throw new IllegalArgumentException();
        };
    }

    public static List<X> xObjects() {
      return List.of(new X(), new X());
    }

    public static List<Y> yObjects() {
        return List.of(new Y(), new Y());
    }

For both cases I get compiler error, e.g. for first case: java.lang.Class<T>' cannot be safely cast to 'java.lang.Class<X>'

This is quite surprising as I expected that switch case logic just tries to cast in the background to find the correct match.

Any idea how to get matching by class working? (Matching by object types is not the point here). Is it a java limitation, like maybe class matching is not supported?

UPDATE:

I tried to use the class name instead, also not working. "Constant expression required" at cases xName, yName. However, I don't see how xName, yName are not constant. As far as I understand they should be also compile time constant.

        public static <T> List<T> switchByClassString(Class<T> clazz) {
        final String xName = X.class.getName();
        final String yName = Y.class.getName();

        return switch (clazz.getClass().getName()) {
            case xName -> (List<T>) xObjects();
            case yName-> (List<T>) yObjects();
            default -> throw new IllegalArgumentException();
        };
    }

UPDATE 2:

In the meantime I guess it is easier to be solved by OOP like:

interface A {
    <T extends A> List<T> getObjects();
}

class X implements A {
    @Override
    public List<X> getObjects() { return List.of(new X(), new X());}
}

class Y implements A {
    @Override
    public List<Y> getObjects() { return List.of(new Y(), new Y());}
}
syr
  • 836
  • 1
  • 12
  • 28
  • The type hierarchy `X subtype of A` does not automatically imply the type hierarchy `Class subtype of Class`. This is the same reason, why a `List` is not a subtype of `List`. – Seelenvirtuose Mar 05 '22 at 11:23
  • @Seelenvirtuose Yes that's right. However, I expected that switch case logic just tries to cast in the background to find the correct match. – syr Mar 05 '22 at 14:44
  • I realize this is just example code, but… in this case, you would not pass the class as an argument. The method would take a `Supplier` argument, which the caller would pass as a constructor reference, like `X::new` or `Y::new`. – VGR Mar 05 '22 at 20:54
  • Matching by object worked, e.g. `switchByClass(new X())`, however, I was actually looking for passing the the class like `switchByClass(X.class)`. In the meantime I think it could be generally an indication for an antipattern. Moving xObjects/yObjects to X and Y respectively as getObjects() each, and defining getObjects() abstract in A would be the more OOP way, so X and Y have their belonging methods defined in itself. – syr Mar 06 '22 at 19:04

0 Answers0