3

I'm using Wicket 6/Java 8 and am adding some simple classes that make use of the lambda functionality from Java 8 (I know the later versions of Wicket have lambda support but we can't upgrade right now). I'm creating a LambdaModel that is a bit like the PropertyModel, which I'm hoping will remove the need to hardcode Strings representing the nested path to the property.

To start, I'm making a simple readonly version. Ive made Serializable versions of the Function interface to create the following:

public class LambdaModelUtils {
  public static <X,R> IModel<R> ofNested( IModel<X> target, SerializableFunction<?,?>... path ) {
     // creates a model that works through each function in the path in turn
  }
}

My implementation works well, but the only problem is that calling this method the 'efficient' way causes compile errors:

IModel<Parent> parentModel = ...
IModel<String> model = LambdaModelUtils.ofNested( parentModel,
                            Parent::getChild, Child::getName );  // Compile time error

The only way I can find to call the method is by the following:

SerializableFunction<Parent,Child> path0 = Parent::getChild;
SerializableFunction<Child,String> path1 = Child::getName;
IModel<String> model = LambdaModelUtils.ofNested( parentModel,
                            path0, path1 );  // works

This is a bit clumsy - is there a better way?

Ive looked here but this doesnt seem to work either:

List<SerializableFunction> path = Arrays.asList( Parent::getChild, Child::getName );

Thanks

fancyplants
  • 1,577
  • 3
  • 14
  • 25
  • 1
    Just curious... Why shouldn't you use lambda expressions where you're using method references? – ernest_k May 18 '18 at 09:13
  • 2
    Since `SerializableFunction,?>` would need unchecked casts to use, it is not better than using strings to represent properties, i.e. no compile-time safety at all. – Holger May 18 '18 at 09:42

2 Answers2

3

If you're using these functions to get to a nested property, but don't really use the intermediate results, I'd advice you to just use a lambda expression:

public static <X,R> IModel<R> ofNested(IModel<X> target, SerializableFunction<X, R> path)

IModel<Parent> parentModel = ...
IModel<String> model = LambdaModelUtils.ofNested(parentModel, p -> p.getChild().getName());

This works since the target type of the lambda is now known, instead of the generic SerializedFunction<?, ?>, you get SerialiedFunction<X, R> where X = Parent and R = String.

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
1

I tried something similar to your code. Casting the method references to the functional interface type solves the compilation error:

IModel<String> model =
    LambdaModelUtils.ofNested(parentModel,
                             (SerializableFunction<Parent,Child>) Parent::getChild, 
                             (SerializableFunction<Child,String>) Child::getName);

Not the prettiest solution, but at least it saves you the need to declare the path0 and path1 variables.

Eran
  • 387,369
  • 54
  • 702
  • 768