How to use a map to invoke an action on an object

I want to call a specific setter in a generic piece of code. Of course, I can resort to the case description, but it will grow, so I prefer the Card.

This is what I came up with:

public class Tester {

private static final Map<String, Setter<Target, ?>> MY_SETTERS = new HashMap<>();
static {
    MY_SETTERS.put("SOURCE1",  ( Target t, Source1 s ) -> t.setSource1( s ) );
    MY_SETTERS.put("SOURCE2",  ( Target t, Source2 s ) -> t.setSource2( s ) );
}

@FunctionalInterface
private interface Setter<T, S> {

    void set( T target, S source );
}

public static void main( String[] args ) {

    Target t = new Target();
    MY_SETTERS.get( "SOURCE1" ).set( t, new Source1() );
}}

      

However, this gives me "incompatible types: Source1 cannot be converted to CAP # 1 where CAP # 1 is a new type variable: CAP # 1 extends the object from capture?"

I understand why his failure. However, is there an elegant way to do this without resorting to the case description?

+3


source to share


1 answer


Because of this type of wildcard on the map, you have to draw the string somewhere. It's a little ugly, but this is what I sometimes do:

Define a generic helper method to differentiate Setter

from your requested type:

public static <T, S> Setter<T, S> getSetter(String id) {
    return (Setter<T, S>) MY_SETTERS.get(id);
}

      

Extract and call the setter like this:



getSetter("SOURCE1").set(t, new Source1());

      

Java will infer the type arguments from your passed parameters and the call itself will look fine. You will get complaints from the compiler because of this unverified actor though.

Obviously, you have to be absolutely sure that you are asking what you expect to receive, otherwise you will receive ClassCastException

. For example. doing the following will throw the specified exception as you are retrieving the setter for Source1

, but calling it with Source2

:

getSetter("SOURCE1").set(t, new Source2());

      

+1


source







All Articles