2

I have the following code where the Binding.createStringBinding(...) part is going to be repeated many many times, the only difference is the method used, i.e. getA(), getB() , getC()

    this.attributeA.bind(Bindings.createStringBinding(() -> {
        if(webService.getLastValue() != null){
            return webService.getLastValue().getA();
        } else{
            return "";
        }
    }, webService.lastValueProperty()));

    this.attributeB.bind(Bindings.createStringBinding(() -> {
        if(webService.getLastValue() != null){
            return webService.getLastValue().getB();
        } else{
            return "";
        }
    }, webService.lastValueProperty()));

New: This is the part of the code that I want to make reusable:

Bindings.createStringBinding(() -> {
            if(webService.getLastValue() != null){
                return webService.getLastValue().getB();
            } else{
                return "";
            }
        }, webService.lastValueProperty())

How can I make this reusable? Perhaps making this a function ?

st202
  • 23
  • 4

3 Answers3

4

Maybe something like this:

private Binding createBinder(final Supplier<String> lambda) {
    return Bindings.createStringBinding(() -> {
        if(webService.getLastValue() != null){
            return lambda.get();
        } else{
            return "";
        }
    }
}

called like

this.attributeA.bind(createBinder(() -> webService.getLastValue().getA()), webService.lastValueProperty());
this.attributeB.bind(createBinder(() -> webService.getLastValue().getB()), webService.lastValueProperty());
Joshua
  • 2,932
  • 2
  • 24
  • 40
  • There is an error in the parameter `lambda`, `Syntax error, insert "... VariableDeclaratorId" to complete FormalParameterList` – st202 Oct 13 '15 at 13:53
  • As I said, the data type is not correct because i couldn't recall it. I wanted you to find it because you should be able to invest some work yourself. I'll update my answer though. – Joshua Oct 13 '15 at 13:54
  • So with the `Supplier` interface, we pass method as parameter without separately creating an interface mentioned in these answers http://stackoverflow.com/questions/2186931/java-pass-method-as-parameter? – st202 Oct 13 '15 at 14:34
  • Exactly. The `Supplier` interface belongs to the JDK 8 and it's sole purpose is to provide a mapping for certain lambda expressions. – Joshua Oct 13 '15 at 14:57
1

A slight variation on @Joshua's answer. Here ObjectTest is the type returned by webService.getLastValue().

private void makeBinding(StringProperty property, Function<ObjectTest, String> propertyAccessor) {
   property.bind( Bindings.createStringBinding(() -> {
        ObjectTest lastValue = webService.getLastValue();
        if (lastValue == null) {
            return "" ;
        } else return propertyAccessor.apply(lastValue);
    }, webService.lastValueProperty()) );
}

And now you do

makeBinding(attributeA, ObjectTest::getA);
makeBinding(attributeB, ObjectTest::getB);

etc

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Why did we have `property` as a parameter, if it is not used in the method? And my properties are all `ReadOnlyStringWrapper` s – st202 Oct 13 '15 at 15:13
  • Sorry, got caught between two different versions of what I intended. See update. `ReadOnlyStringWrapper` is a subclass of `StringProperty`, so this should work fine. – James_D Oct 13 '15 at 15:19
0

Let's suppose attributeA and attributeB both implement the Property<String> interface, and that methods getA, getB, etc. all return a String. With this in mind, you could do:

BiConsumer<Property<String>, Function<ObjectTest, String>> binder = 
    (property, getter) ->
        property.bind(Bindings.createStringBinding(() -> {
            if (webService.getLastValue() != null) {
                return getter.apply(webService.getLastValue());
            } else {
                return "";
            }
        }, webService.lastValueProperty()));

This code creates a BiConsumer (which is a consumer that takes 2 arguments).

The first argument is an instance of Property<String> (as suggested by @James_D's comment) that is implemented by attributeA and attributeB.

The second argument is a Function<ObjectTest, String>, which is a function that takes an instance of ObjectTest and returns a String. Here I'm using it to represent a generic getter method over the ObjectTest class (more specifically, ObjectTest::getA and ObjectTest::getB).

If you want, you could rewrite the `BiConsumer' in a more java8 friendly way:

BiConsumer<Property<String>, Function<ObjectTest, String>> binder = 
    (property, getter) ->
        property.bind(Bindings.createStringBinding(
            () -> Optional.ofNullable(webService.getLastValue())
                .map(getter).orElse(""),
            webService.lastValueProperty()));

To use it:

binder.accept(this.attributeA, ObjectTest::getA);
binder.accept(this.attributeB, ObjectTest::getB);

The code above assumes that methods getA, getB, etc. return a String.

You might want to further read about Optional and BiConsumer in the javadocs.

fps
  • 33,623
  • 8
  • 55
  • 110
  • I assume the interface in question is actually [`Property`](http://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/Property.html). (I like the use of `Optional` though.) – James_D Oct 13 '15 at 15:39
  • @James_D I don't know anything about javafx, thanks for the input. – fps Oct 13 '15 at 15:57