Convert java lambda predicates

Asked

Viewed 156 times

2

I am trying to perform a model transformation using java lambda. Below follows a block of code that exemplifies what I want to do:

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

Thus, I want to retrieve each predicate term and use it to perform 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 java string "{$vara}", the logical operator '==' for another java string "===" and the value '1' for "1". Thus, the return of the translatePrimitivePredicate method would be the concatenation of terms, like, "{$vara} === 1".

How can I do that?

1 answer

3

Picking up a lambda expression for runtime translation is a virtually impossible task(so far), I will try to give you two suggestions:

1 - Think of a simpler solution that doesn’t involve a translation the way you described it;

2 - If you really need to do it that way, I believe 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 think it is not a very interesting solution for production(mainly due to performance).

SOLUTION

Instead of trying to capture the lambda expression at runtime we can make a val of an expression(String) applying the translation and converting the String in a Function.

pom.xml

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

We start by defining a translation interface of the expressions:

public interface FunctionTranslator<T> {

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

    T getFunction();

}

Translator implementation 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;
    }   

}

Implementation of the translator of an expression summing 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;
    }   
}

Implementation of translation strategy:

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 Factory Translator:

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.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.