Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enum of Functions

Let's say I have two classes

class A{
    int a;
    int getA(){
        return this.a;
    }
}

and

class B extends A{
    String b;
    String getB(){
        return this.b;
    }
}

I would like to have an enum, containing all possible values and and getters of inheritance tree (don't ask, I just want to).

enum ValueGetters{
    A("a", A::getA),
    B("b", B::getB);

    String parameterName;
    Function parameterGetter;
}

I have problem writing constructor for this class.

ValueGetters(String parameterName, Function parameterGetter){
    this.parameterName = parameterName;
    this.parameterGetter = parameterGetter;
}

returns error for both A and B (Error:(12, 14) java: incompatible types: invalid method reference).

The same situation is for ValueGetters(String parameterName, Function<?,?> parameterGetter)

For ValueGetters(String parameterName, Function<? extends A,?> parameterGetter) this gives error only for B, and if I try to overload constructor with ValueGetters(String parameterName, Function<? extends B,?> parameterGetter) I have new error that both types have the same type of erasure.

On the other hand ValueGetters(String parameterName, Object parameterGetter) returns error stating that Object is not a Function.

I have tried to define my own @FunctionalInterface but it gave me the same error, and overloading methods of @FunctionalInterface to accept both A and B apparently is not an option (or not an obvious one).

If anyone could propose solution to my problem I would greatly appreciate it.

EDIT & SOLUTION

I know it's not exactly an enum, but it works in the same way and provides functionality I needed:

  1. Returns getter
  2. Getter is type-sensitive
  3. Solution does not require any changes in the original class
  4. Works well with interfaces

...and now, the code:

public class ValueGetter<T extends A, R> {
    private String name;
    private Function<A,R> getter;

    private ValueGetter(String name, Function<A, R> getter){
        this.name = name;
        this.getter = getter;
    }

    private static <T extends A, R> ValueGetter create(String name, Function<T,R> valueGetter){
        return new ValueGetter(name, valueGetter);
    }

    public static ValueGetter<A, Integer> AA = create("a", A::getA);
    public static ValueGetter<B, Integer> BB = create("a", B::getB);

    public Function<T, R> getGetter(){
        return (Function<T, R>) this.getter;
    }
}

With this implementation

A a1 = new A(12345);
B b1 = new B(54321, "sdfghjk");
System.out.println(ValueGetter.AA.getGetter().apply(a1));
System.out.println(ValueGetter.AA.getGetter().apply(b1));
System.out.println(ValueGetter.BB.getGetter().apply(b1));

compiles and works, while line

System.out.println(ValueGetter.BB.getGetter().apply(a1));

gives compilation error apply(B) in function cannot be applied to (A)

like image 331
Karol Pokomeda Avatar asked May 30 '26 14:05

Karol Pokomeda


1 Answers

One waty to implement it is using a singleton instance of each class:

class BB {  // Renamed B to BB to make it work with enum
    String b;
    private static final BB instance = new BB();


    public static BB getInstance() {
        return instance;
    }


    public String getB(){
        return this.b;
    }

    // Example usage with cast
    public String getB(Object b) {
        return ((BB) b).getB();
    }
}

public enum ValueGetters{
    B("b", BB.getInstance()::getB);

    String parameterName;
    Function parameterGetter;

    ValueGetters(String parameterName, Function parameterGetter){
        this.parameterName = parameterName;
        this.parameterGetter = parameterGetter;
    }
}

You could the use it like that:

ValueGetters.B.getGetter().apply(b);
like image 151
syntagma Avatar answered Jun 02 '26 04:06

syntagma



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!