Hello everyone,
I just saw yesterday, that the IModel became/will become a @FunctionalInterface 
in Wicket 8 and was very happy about it. I am also very happy about the ongoing 
implementations and discussions around lambda usage in Wicket, because it 
simplifies a lot of code.
Now, one thing I have been working on, is implementing some of the now known 
methods of Stream<T> for a AbstractReadOnlyModel and also for other things - 
like columns. I have not seen such discussions on here, please forgive me if I 
missed that. If it has indeed not been discussed and you find the idea useful, 
you can take a look at an implementation in the following repository: 
https://github.com/noobymatze/lambdawicket-model/blob/master/src/main/java/com/github/noobymatze/lambdawicket/model/ReadOnlyModel.java

What might we be able to do with that? 
Consider a Person containing an Address, containing a Street with a name. Now I 
want to display the name of the street. How would I go about that?new 
Label("streetName", () -> person.getAddress().getStreet().getName());
This is one approach, but it completely ignores the possibility of null values 
and a default value for such cases. I could wrap the above in an Optional or 
create a method in the Person class like 'Optional<String> getStreetName() 
{...}'. 

With the proposed ReadOnlyModel I could also do it in the following way:
new Label("streetName", ReadOnlyModel.of(person).  map(Person::getAddress).  
map(Address::getStreet).  map(Street::getName).  orElse("n/a"));
But that's not all. Imagine we would need to dynamically truncate the 
streetName based on user input:
IModel<WicketFunction<String, String>> truncate = () -> str -> str.length() > 
10 ? str.substring(0, 10) + "..." : str;
IModel<String> truncatedStreetName = ReadOnlyModel.of(person).    
map(Person::getAddress).    map(Address::getStreet).    map(Street::getName).   
 apply(truncate).    orElse("n/a");
Now we could switch the truncate Model using a 
DropDownChoice<WicketFunction<String, String>> or by just setting the contained 
function somewhere.truncate.setObject(str -> str.substring(0, 20));

The whole approach is - if I am not mistaken - heavier on memory, because 
instead of one IModel<String> we now have 5 or 6 Models, that cannot be garbage 
collected, because they are all needed to perform the computation.

This doesn't apply for mapping over an IColumn though, because it doesn't need 
to rely on the laziness, like the ReadOnlyModel does (otherwise a change in 
truncate wouldn't mean a change in the final value), so:new 
LambdaColumn(of("Name"), Person::getAddress).  map(Address::getStreet).  
map(Street::getName).  orElse("n/a"));
would create 4 new instances of the LambdaColumn, but 3 of them could be gc'd 
more or less the second they were created - like I said, if I am not mistaken.
If this is at all an approach you think might be useful, I would be happy to 
provide the implementation of the LambdaColumn. Otherwise just ignore my 
message. :)
Have a nice day,Matthias

Reply via email to