2

I got in this situation recently where I was creating a system of defined arguments to be provided to build messages based on an enum to ensure that every element is present in the dynamic args and so that the types are correctly checked on the arguments not to provide a nonsensical arg.

Here is my code:

interface ParamList { Class<?> paramType(); }
@AllArgsConstructor
enum ParamType extends ParamList {
    FOO(Foo.class),
    BAR(Bar.class);

    @Getter
    private final Class<?> paramType;
}
class MessageParams<T extends Enum<T> & ParamList> {

    private Map<T, Object> args;

    // constructor...

    public <U> MessageArgs<T> put(T key, U value) {
        args.put(key, value);
        return this;
    }

    // get...
}

My problem is int he last class: MessageParams. I wonder if I could enforce the U value to be the paramType() of the provided T at compile-time (I omitted here my runtime check) so that I don't need to explicitly provide the generic when calling put to get correct hinting.

RedDev
  • 35
  • 5
  • Nah, even though `FOO` and `BAR` are classes, they're synthetic enum classes so you can't tie them into generics. – Kayaman Aug 26 '23 at 15:15
  • So there is absolutely no way to tie the `U` in put to the param in the enum values? – RedDev Aug 26 '23 at 15:16
  • What version of Java do you use ? – Bastien Aracil Aug 26 '23 at 15:17
  • I'm using Java 17 – RedDev Aug 26 '23 at 15:20
  • No, the enum values aren't even proper classes they're instances of the enum as seen [here](https://stackoverflow.com/q/31039980/2541560). I remembered that they were subclasses like `Enum$FOO` but they're actually instances and you can't work with instances in generics. – Kayaman Aug 26 '23 at 15:21
  • I know that there are instances. But without proper case classes added to Java I won't be able to get my type checking right? – RedDev Aug 26 '23 at 15:22
  • As @Kayaman wrote, this is not possible with enum. You could used sealed interface. This is not an enum but it has some kin of "enumeration" property. – Bastien Aracil Aug 26 '23 at 15:22
  • But with sealed interfaces the syntax will become a lot more cluttered, I wanted to keep it simple :/ – RedDev Aug 26 '23 at 15:24
  • 1
    Then, forget enum. Define ParamType with a generic, and instantiate instances directly in the interface as static members. – Bastien Aracil Aug 26 '23 at 15:25
  • I agree with Bastien. Make your own pseudo-enum class with a private constructor and public static members that each have their own generic type. An example of this is [StandardSocketOptions](https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/net/StandardSocketOptions.html). – VGR Aug 26 '23 at 18:54

1 Answers1

1

You are asking a very similar question to what I asked a while ago.

Long story short, the current makers of Java are well aware of this issue, and they tried to fix it, but decided that it was too much effort a few years back.

Here is a link to their official attempt -- https://openjdk.org/jeps/301

Here is a link to where they announced that they were giving up -- https://mail.openjdk.org/pipermail/amber-spec-experts/2017-May/000041.html

Here is their second attempt -- https://mail.openjdk.org/pipermail/amber-spec-experts/2018-December/000876.html

Here is me asking them for more context -- https://mail.openjdk.org/pipermail/amber-dev/2023-March/thread.html#7914

As well as here -- https://mail.openjdk.org/pipermail/amber-dev/2023-March/thread.html#7932

davidalayachew
  • 1,279
  • 1
  • 11
  • 22
  • 1
    So disappointing, thank you for the answer. – RedDev Aug 26 '23 at 22:35
  • You and me both. I said in the mailing list, but if it weren't for this, I think enums would be perfect. This is literally their single, solitary flaw. And Java has better enums than literally any other non-JDK language out there. One of the few things Java can claim to be unparalleled at. – davidalayachew Aug 26 '23 at 23:16