Convert lambda java predicates

2

I'm trying to do a template transformation using java lambda. Here is a code block that exemplifies what I want to do:

public String translatePrimitivePredicate(){
    Predicate<Integer> predicate = a -> a == 1;     
    return translate(predicate) //"{$varA} === 1";
}

So, I want to retrieve each term from the predicate and use it to execute a business logic. Using the above example, the conversion would be executed in such a way that the term 'a' would be translated into a string java "{$ varA}", the logical operator '==' for another string java "===" and the value '1' to '1'. Thus, the return of the translatePrimitivePredicate method would be the concatenation of terms, such as, "{$ varA} === 1".

How can I do this?

    
asked by anonymous 27.12.2017 / 01:16

1 answer

2

Getting a lambda expression for translation at runtime is a virtually impossible task (so far), I'll try to give you two suggestions:

1 - Think of a simpler solution that does not involve a translation in the way you described;

2 - If you really need to do this, I believe the lambda-from-string can help you with a slightly different solution (Function instead of Predicate).

I tried to simplify as much as I could, but still I still do not think it's a very interesting solution for production (mainly due to performance).

SOLUTION

Instead of trying to catch the lambda expression at runtime we can eval of an expression (String) by applying the translation and converting the String into a > Function .

pom.xml

<dependency>
    <groupId>pl.joegreen</groupId>
    <artifactId>lambda-from-string</artifactId>
    <version>1.6</version>
</dependency>

We started by defining an expression translation interface:

public interface FunctionTranslator<T> {

    void eval(String lambda, LambdaFactory factory) throws LambdaCreationException;

    T getFunction();

}

Implementing the translator of an expression that compares integers:

public class CompareIntegersFunctionTranslator implements FunctionTranslator<Function<Integer, Boolean>> {

    private final String TRANSLATOR_PATTERN = "{$var%s} === %s";
    private final TypeReference<Function<Integer, Boolean>> TYPE_REFERENCE = new TypeReference<Function<Integer,Boolean>>(){};

    private String translatedLambda;
    private Function<Integer, Boolean> function;

    @Override
    public void eval(String lambda, LambdaFactory factory) throws LambdaCreationException {
        this.function = factory.createLambda(lambda, TYPE_REFERENCE);       
        this.translatedLambda = translate(lambda);
    }

    @Override
    public Function<Integer, Boolean> getFunction() {
        return function;
    }

    private String translate(String expression) {
        String [] splited = expression.split("");
        return String
            .format(TRANSLATOR_PATTERN, 
                    splited[0].toUpperCase(), 
                    splited[splited.length - 1]);
    }

    @Override
    public String toString() {
        return translatedLambda;
    }   

}

Implementing the translator of an expression that sums integers:

public class SumIntegersFunctionTranslator implements FunctionTranslator<Function<Integer, Integer>> {

    private final String TRANSLATOR_PATTERN = "{$var%s} += 1";
    private final TypeReference<Function<Integer, Integer>> TYPE_REFERENCE = new TypeReference<Function<Integer, Integer>>(){};

    private String translatedLambda;
    private Function<Integer, Integer> function;

    @Override
    public void eval(String lambda, LambdaFactory factory) throws LambdaCreationException {
        this.function = factory.createLambda(lambda, TYPE_REFERENCE);       
        this.translatedLambda = translate(lambda);      
    }

    @Override
    public Function<Integer, Integer> getFunction() {
        return function;
    }

    private String translate(String expression) {
        String [] splited = expression.split("");
        return String
            .format(TRANSLATOR_PATTERN, 
                    splited[0].toUpperCase(), 
                    splited[splited.length - 1]);
    }

    @Override
    public String toString() {
        return translatedLambda;
    }   
}

Translation strategy implementation:

public enum FunctionTranslatorStrategy {

    COMPARE_INTEGERS(new CompareIntegersFunctionTranslator()),
    SUM_INTEGERS(new SumIntegersFunctionTranslator());

    FunctionTranslator<?> translator;

    FunctionTranslatorStrategy(FunctionTranslator<?> translator) {      
        this.translator = translator;
    }

    public FunctionTranslator<?> getFunctionTranslator() {
        return translator;
    }

}

Implementation of a translator factory:

public class FunctionFactory {

    private static final LambdaFactory LAMBDA_FACTORY = LambdaFactory.get();

    @SuppressWarnings("unchecked")
    public static <T> FunctionTranslator<T> create(
            String lambda, 
            FunctionTranslatorStrategy strategy) throws LambdaCreationException {

        FunctionTranslator<T> translator = (FunctionTranslator<T>) strategy.getFunctionTranslator();
        translator.eval(lambda, LAMBDA_FACTORY);

        return translator;      
    }

}

Testing:

public static void main(String[] args) throws LambdaCreationException {

    FunctionTranslator<Function<Integer, Boolean>> compare = FunctionFactory
            .create("a -> a == 1", 
                    FunctionTranslatorStrategy.COMPARE_INTEGERS);

    System.out.println(compare.toString());             // {$varA} === 1
    System.out.println(compare.getFunction().apply(1)); // true
    System.out.println(compare.getFunction().apply(2)); // false

    FunctionTranslator<Function<Integer, Integer>> sum = FunctionFactory
            .create("b -> b + 1",
                    FunctionTranslatorStrategy.SUM_INTEGERS);       

    System.out.println(sum.toString());             // {$varB} += 1
    System.out.println(sum.getFunction().apply(1)); // 2
    System.out.println(sum.getFunction().apply(2)); // 3
}

Note that there is repeated code and the translation method is very basic (maybe regex to improve). It is possible to greatly improve this implementation and make things simpler, this is just an idea of where to go.

    
29.12.2017 / 18:38