DynamicReports reportParameters.getFieldValue() returns wrong value

253 views Asked by At

I have following AbstractSimpleExpression<Boolean> to color some text:

private class UtilisationExpression extends AbstractSimpleExpression<Boolean> {
    private static final long serialVersionUID = 1L;
    private String variableName;
    private String fieldName;

    public UtilisationExpression(String variableName, String fieldName) {
        this.variableName = variableName;
        this.fieldName = fieldName;

    }

    @Override
    public Boolean evaluate(ReportParameters reportParameters) {
        return ((Double) reportParameters.getVariableValue(variableName)
                / (Double) reportParameters.getFieldValue(fieldName) * 100) > 100;
    }
}

The text coloring is set up as following (initializeStyle() method includes this. Called before anything else):

conditionalFontColorRedMarketValue = stl
        .conditionalStyle(new UtilisationExpression("marketValueSum", "bucket.marketValueLimit"))
        .setForegroudColor(Color.RED);
subTotalStyleBottomBordersRightRedColorMarketValue = stl.style(subTotalStyleBottomBordersRight)
        .addConditionalStyle(conditionalFontColorRedMarketValue).setLinePen(stl.pen1Point());
subTotalStyleBottomBordersRightRedColorMarketValue.getStyle().getBorder().getBottomPen()
                .setLineColor(Color.BLACK);

Then we have the usage within the report, which is a bit more complex, as I work with grouping etc. I will include everything I deem necessary:

VariableBuilder<Double> valueInEurSumGrp = DynamicReports.variable("marketValueSum", valueInEurColumn,
        Calculation.SUM);
CustomGroupBuilder bookGroup = grp.group("bucketGroup", new BucketExpression()).groupByDataType()
        .setShowColumnHeaderAndFooter(true).setHeaderLayout(GroupHeaderLayout.VALUE).setPadding(0)
        .setStyle(titleStyle).addHeaderComponent(cmp.filler().setFixedHeight(5))
        .addFooterComponent(cmp.filler().setFixedHeight(10)).setReprintHeaderOnEachPage(true)
        .setMinHeightToStartNewPage(15)
        .setPrintSubtotalsWhenExpression(new PrintSubtotalsExpression(valueInEurSumGrp)).keepTogether();
valueInEurSumGrp.setResetGroup(bookGroup);
valueInEurSumGrp.setResetType(Evaluation.GROUP);
FieldBuilder<Double> marketValueLimitField = field("bucket.marketValueLimit", type.doubleType());
// Usage in subtotals
builder.setSubtotalStyle(subTotalStyleNoBordersLeft)
        .subtotalsAtGroupFooter(bookGroup,
                ReportCommon.createSubtotalColumns(subTotalStyleNoBordersLeft,
                        ReportCommon.convertSubtotalsToList(
                                sbt.text("Limit", bookColumn).setStyle(subTotalStyleNoBordersLeft), sbt
                                        .aggregate(marketValueLimitField, valueInEurColumn,
                                                Calculation.NOTHING)
                                        .setStyle(subTotalStyleNoBordersRight).setPattern("#,##0")),
                        columns.toArray(new TextColumnBuilder<?>[] {})))

        .setSubtotalStyle(subTotalStyleBottomBordersLeft)
        .subtotalsAtGroupFooter(bookGroup, ReportCommon.createSubtotalColumns(
                subTotalStyleBottomBordersLeft,
                ReportCommon.convertSubtotalsToList(
                        sbt.text("Utilisation", bookColumn).setStyle(subTotalStyleBottomBordersLeft),
                        sbt.aggregate(
                                new PercentageExpression("bucket.marketValueLimit", valueInEurSumGrp),
                                valueInEurColumn, Calculation.NOTHING)
                                .setStyle(subTotalStyleBottomBordersRightRedColorMarketValue)),
                columns.toArray(new TextColumnBuilder<?>[] {})))
        .addSummary(cmp.filler().setFixedHeight(15));

And for comparison, the PercentageExpression, which manages to calculate the right percentage:

private class PercentageExpression extends AbstractSimpleExpression<String> {
    private static final long serialVersionUID = 1L;

    private String fieldName;
    private VariableBuilder<Double> valueInEurColumn;

    public PercentageExpression(String fieldName, VariableBuilder<Double> valueInEurSum) {
        this.fieldName = fieldName;
        this.valueInEurColumn = valueInEurSum;
    }

    @Override
    public String evaluate(ReportParameters reportParameters) {
        Double percentage = reportParameters.getValue(valueInEurColumn)
                / (double) reportParameters.getFieldValue(fieldName) * 100;
        return String.format("%,.2f %%", percentage);
    }
}

I have omitted some code like initialization of columns and other styles as well as a good part of the report itself, as that has nothing to do with the issue at hand.

The actual issue is, that reportParameters.getFieldValue("bucket.marketValueLimit") in the UtilisationExpression fetches the wrong value, as soon as the data is grouped in more than 1 block. If I only have 1 group, it works fine, but as soon as I have 2 or more groups, that method just can't fetch the right value.

I have done some code digging and found that the faulty method call delegates to JRAbstractScriptlet#getFieldValue(String fieldName). In that method it looks at Map<String,JRFillField> fieldsMap; which contains all the fields. Then I found the field I was searching for and inspected the JRFillField which holds following value fields:

private Object previousOldValue;
private Object oldValue;
private Object value;
private Object savedValue;

previousOldValue and value are the wrong value, while savedValue is null and oldValue holds the value I'd expect. It seems that the values are already set up for the next group, before the current group was finished properly by subtotals. It seems that one could actually access the oldValue if it would be possible to access the JRFillField directly, but I couldn't find a way to do that as well.

I already tried to set it up like PercentageExpression (using VariableBuilder), but it has the same effect...

Does anyone has an idea, why the method call returns the wrong values for each group? And how can I fix this issue?


Sorry for all that info I dumped here, I am not sure what is necessary to solve this issue. If you need more info, just ask

1

There are 1 answers

0
XtremeBaumer On

I found a way to circumvent this issue. Instead of using FieldBuilder, I created VariableBuilder from the fields and updated the AbstractSimpleExpression as following:

@Override
public Boolean evaluate(ReportParameters reportParameters) {
    return ((Double) reportParameters.getVariableValue(variableName)
            / (Double) reportParameters.getVariableValue(fieldName) * 100) > 100;
}

Setting up the coloring:

conditionalFontColorRedMarketValue = stl
        .conditionalStyle(new UtilisationExpression("marketValueLimit", "bucketMarketValueLimit"))
        .setForegroudColor(Color.RED);
conditionalFontColorRedRiskValue = stl
        .conditionalStyle(new UtilisationExpression("valueAtRiskLimit", "bucketValueAtRiskLimit"))
        .setForegroudColor(Color.RED);

And setting up the fields/variables:

FieldBuilder<Double> marketValueLimitField = field("bucket.marketValueLimit", type.doubleType());
FieldBuilder<Double> valueAtRiskLimitField = field("bucket.valueAtRiskLimit", type.doubleType());

VariableBuilder<Double> marketValueLimitVariable = DynamicReports.variable("bucketMarketValueLimit",
        marketValueLimitField, Calculation.NOTHING);
VariableBuilder<Double> valueAtRiskLimitVariable = DynamicReports.variable("bucketValueAtRiskLimit",
        valueAtRiskLimitField, Calculation.NOTHING);

I am still not sure why variables work as expected and fields do not