JEXLFunction.java

package fr.inrae.agroclim.indicators.model.function.aggregation;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.Map;

import fr.inrae.agroclim.indicators.exception.IndicatorsException;
import fr.inrae.agroclim.indicators.model.JEXLFormula;
import jakarta.xml.bind.annotation.XmlRootElement;
import lombok.EqualsAndHashCode;

/**
 * JEXL implementation of the aggregation function.
 *
 * For the syntax allowed check
 * http://commons.apache.org/proper/commons-jexl/reference/syntax.html
 *
 * @author jcufi
 */
@XmlRootElement
@EqualsAndHashCode(
        callSuper = true
        )
public final class JEXLFunction extends AggregationFunction {
    /**
     * UUID for Serializable.
     */
    private static final long serialVersionUID = 3308126437081517191L;

    /**
     * org.apache.commons.jexl2.JexlEngine handler.
     */
    private transient JEXLFormula formula = new JEXLFormula();

    /**
     * Constructor.
     */
    public JEXLFunction() {
        super();
    }

    @Override
    public double aggregate(final Map<String, Double> values) throws IndicatorsException {
        formula.setExpression(getExpression());
        return formula.evaluate(values, Double.class);
    }

    @Override
    public boolean isValid() {
        formula.setExpression(getExpression());
        return formula.isValid();
    }

    /**
     * Context: Deserialization does not initialize formula.
     *
     * A final field must be initialized either by direct assignment of an initial value or in the constructor. During
     * deserialization, neither of these are invoked, so initial values for transients must be set in the
     * 'readObject()' private method that's invoked during deserialization. And for that to work, the transients must
     * be non-final.
     *
     * @param ois input stream from deserialization
     */
    private void readObject(final ObjectInputStream ois) throws ClassNotFoundException, IOException {
        // perform the default de-serialization first
        ois.defaultReadObject();
        formula = new JEXLFormula();
    }

    @Override
    public String toString() {
        return "JEXLFunction [getExpression()=" + formula.getExpression() + "]";
    }

}