Jonathan Pullano
Jonathan Pullano

Reputation: 322

Lambda representing a getter method from either a parent class or a child class

I have some code below representing a parent and child Pojo, and a simple validator that pulls two values off them representing ranges, to verify that start < end. I want to validator to be generic enough that it can accept two field getter methods at construction time, and then be able to be passed a POJO to perform the range check on. However, I have been unable to get this to type check properly. I have tried having the validator constructor taking all of the following:

Function<Pojo, Integer> //Fails on constructing vlad2 - "Incompatible types in lambda expression: Expected Pojo but found ExtendedPojo".

Function<? extends Pojo, Integer> //Fails on getRangeStart.apply(pojo) - "(capture<? extends Pojo>) in Function cannot be applied to Pojo"

Function<Object, Integer> //Fails on constructing both vlad and vlad2 - "Incompatible types in lambda expression: Expected Object but found ExtendedPojo"

Code:

import java.util.function.Function;

class Pojo {

  private Integer rangeOneStart;
  private Integer rangeOneEnd;

  public Pojo(Integer rangeOneStart, Integer rangeOneEnd) {
    this.rangeOneStart = rangeOneStart;
    this.rangeOneEnd = rangeOneEnd;
  }

  public Integer getRangeOneStart() {
    return rangeOneStart;
  }

  public Integer getRangeOneEnd() {
    return rangeOneEnd;
  }
}

class ExtendedPojo extends Pojo {
  private Integer rangeTwoStart;
  private Integer rangeTwoEnd;

  public ExtendedPojo(Integer rangeOneStart, Integer rangeOneEnd, Integer rangeTwoStart, Integer rangeTwoEnd) {
    super(rangeOneStart, rangeOneEnd);
    this.rangeTwoStart = rangeTwoStart;
    this.rangeTwoEnd = rangeTwoEnd;
  }

  public Integer getRangeTwoStart() {
    return rangeTwoStart;
  }

  public Integer getRangeTwoEnd() {
    return rangeTwoEnd;
  }
}

interface SomeValidatorInterface<T> {
  boolean isValid(T obj);
}

class MyValidator implements SomeValidatorInterface<Pojo> {

  private Function<Pojo, Integer> getRangeStart;
  private Function<Pojo, Integer> getRangeEnd;

  MyValidator(Function<Pojo, Integer> getRangeStart, Function<Pojo, Integer> getRangeEnd) {
    this.getRangeStart = getRangeStart;
    this.getRangeEnd = getRangeEnd;
  }

  @Override
  public boolean isValid(Pojo pojo) {
    Integer start = getRangeStart.apply(pojo);
    Integer end = getRangeEnd.apply(pojo);
    return end > start;
  }
}

class Main {
  public static void main(String args[]) {
    ExtendedPojo pojo = new ExtendedPojo(1,2,3,4);
    MyValidator vlad = new MyValidator(Pojo::getRangeOneStart, Pojo::getRangeOneEnd);
    System.out.println(vlad.isValid(pojo));

    MyValidator vlad2 = new MyValidator(ExtendedPojo::getRangeTwoStart, ExtendedPojo::getRangeTwoEnd);
    System.out.println(vlad2.isValid(pojo));
  }
}

Upvotes: 0

Views: 281

Answers (1)

m.antkowicz
m.antkowicz

Reputation: 13571

Since the validator is being used per instance just provide a specific instance method as Supplier<Integer>

MyValidator(Supplier<Integer> getRangeStart, Supplier<Integer> getRangeEnd) {
    this.getRangeStart = getRangeStart;
    this.getRangeEnd = getRangeEnd;
}

// ...

ExtendedPojo pojo = new ExtendedPojo(1,2,3,4);
MyValidator vlad = new MyValidator(pojo::getRangeOneStart, pojo::getRangeOneEnd);

If you don't want to use such specific construction you need to move the range getter to the common interface or at least the Pojo class and override this in ExtendedPojo

Upvotes: 1

Related Questions