title: Using a CustomExpression in a DynamicJasper chart
body: <p>I have a project using DynamicJasper to create reports. It works fine so far, but when I wanted to add a chart to a previously functional report I run into issues.</p>
  
  <p>I keep getting this:</p>
  
  <blockquote>
    <p>net.sf.jasperreports.engine.design.JRValidationException: Report design not valid :
         1. Field not found : customExpression_for_Ganancia
        at net.sf.jasperreports.engine.design.JRAbstractCompiler.verifyDesign(JRAbstractCompiler.java:258)
        at net.sf.jasperreports.engine.design.JRAbstractCompiler.compileReport(JRAbstractCompiler.java:140)
        at net.sf.jasperreports.engine.JasperCompileManager.compileReport(JasperCompileManager.java:215)
        at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperReport(DynamicJasperHelper.java:519)
        at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperPrint(DynamicJasperHelper.java:279)
        at ar.com.fdvs.dj.core.DynamicJasperHelper.generateJasperPrint(DynamicJasperHelper.java:232)</p>
  </blockquote>
  
  <p>Ganancia being the only column in the chart that is a CustomExpression. If I don't add this column as a series to the chart, the chart renders properly. It seems the chart doesn't play well with expressions...</p>
  
  <p>A snippet from my code:</p>
  
  <pre><code>private DynamicReport buildSalesReport() throws ColumnBuilderException, ClassNotFoundException, ChartBuilderException {
  
      DynamicReportBuilder drb = new DynamicReportBuilder();
  
      drb.setReportName("Reporte de Ventas")
          .setTitle("Reporte de ventas")
          .setSubtitle("Este reporte fue generado el " + new Date())
          .setPrintColumnNames(false)
          .setIgnorePagination(true)
          .setMargins(10, 10, 10, 10)
          .setUseFullPageWidth(true);
  
      Style groupOneStyle = new Style();
              groupOneStyle.setFont(Font.ARIAL_BIG);
              groupOneStyle.setHorizontalAlign(HorizontalAlign.LEFT);
              groupOneStyle.setVerticalAlign(VerticalAlign.MIDDLE);
  
      AbstractColumn columnDisplayName = ColumnBuilder.getNew()
              .setColumnProperty("bookingType.displayName", String.class.getName())
              .setTitle("Tipo").setWidth(new Integer(40))
              .setStyle(groupOneStyle)
              .build();
  
      AbstractColumn columnDestiny = ColumnBuilder.getNew()
              .setColumnProperty("bookedObject.destiny", String.class.getName())
              .setTitle("Destino").setWidth(new Integer(40))
              .build();
  
      Style priceStyle = new Style();
      priceStyle.setHorizontalAlign(HorizontalAlign.RIGHT);
  
      AbstractColumn columnCurrency = ColumnBuilder.getNew()
              .setColumnProperty("bookedObject.currency.displayName", String.class.getName())
              .setTitle("Cotizacion").setWidth(new Integer(5))
              .setShowText(false)
              .build();
  
      Style footerStyle = new Style();
              footerStyle.setFont(Font.ARIAL_MEDIUM);
              footerStyle.setBorderTop(Border.THIN);
              footerStyle.setHorizontalAlign(HorizontalAlign.RIGHT);
              footerStyle.setVerticalAlign(VerticalAlign.MIDDLE);
  
      AbstractColumn columnPrice = ColumnBuilder.getNew()
              .setColumnProperty("bookedObject.price", Double.class.getName())
              .setStyle(priceStyle)
              .setPattern("$ 0.00")
              .setTitle("Precio").setWidth(new Integer(25))
              .build();
  
      AbstractColumn columnCount = ColumnBuilder.getNew()
              .setColumnProperty("count", Integer.class.getName())
              .setStyle(priceStyle)
              .setTitle("Cantidad").setWidth(new Integer(25))
              .build();
  
      columnCount.setName("Cantidad");
  
      AbstractColumn columnProfit = ColumnBuilder.getNew()
          .setCustomExpression(this.getProfitExpression())
          .setStyle(priceStyle)
          .setTitle("Ganancia").setWidth(new Integer(20))
          .setPattern("$ 0.00")
          .build();
  
      columnProfit.setName("Ganancia");
  
      GroupBuilder groupBookingTypeBuilder = new GroupBuilder();
      DJGroup groupBookingType =
          groupBookingTypeBuilder.setCriteriaColumn((PropertyColumn) columnDisplayName)
              .setGroupLayout(GroupLayout.VALUE_IN_HEADER_WITH_HEADERS_AND_COLUMN_NAME)
              .build();
  
      GroupBuilder groupCurrencyBuilder = new GroupBuilder();
      DJGroup groupCurrency =
          groupCurrencyBuilder.setCriteriaColumn((PropertyColumn) columnCurrency)
              .addFooterVariable(columnCount,DJCalculation.SUM,footerStyle)
              .addFooterVariable(columnProfit,DJCalculation.SUM,footerStyle)
              .setGroupLayout(GroupLayout.VALUE_IN_HEADER)
              .build();
  
      drb.addColumn(columnDisplayName)
          .addColumn(columnCurrency)
          .addColumn(columnDestiny)
          .addColumn(columnCount)
          .addColumn(columnPrice)
          .addColumn(columnProfit)
          .addGroup(groupBookingType)
          .addGroup(groupCurrency)
          .setPrintBackgroundOnOddRows(true);
  
      DJAxisFormat categoryAxisFormat = new DJAxisFormat("Destino");
      categoryAxisFormat.setLabelFont(Font.ARIAL_SMALL);
      categoryAxisFormat.setLabelColor(Color.DARK_GRAY);
      categoryAxisFormat.setTickLabelFont(Font.ARIAL_SMALL);
      categoryAxisFormat.setTickLabelColor(Color.DARK_GRAY);
      categoryAxisFormat.setTickLabelMask("");
      categoryAxisFormat.setLineColor(Color.DARK_GRAY);
  
      DJAxisFormat valueAxisFormat = new DJAxisFormat("Ventas / Ingresos");
      valueAxisFormat.setLabelFont(Font.ARIAL_SMALL);
      valueAxisFormat.setLabelColor(Color.DARK_GRAY);
      valueAxisFormat.setTickLabelFont(Font.ARIAL_SMALL);
      valueAxisFormat.setTickLabelColor(Color.DARK_GRAY);
      valueAxisFormat.setTickLabelMask("#,##0");
      valueAxisFormat.setLineColor(Color.DARK_GRAY);
  
      DJChart djChart = new DJBarChartBuilder()
              //chart
              .setX(20)
              .setY(10)
              .setWidth(500)
              .setHeight(250)
              .setCentered(false)
              .setBackColor(Color.LIGHT_GRAY)
              .setShowLegend(true)
              .setPosition(DJChartOptions.POSITION_FOOTER)
              .setTitle(new StringExpression() {
                  @Override
                  public Object evaluate(Map fields, Map variables, Map parameters) {
                      return variables.get("bookingType.displayName");
                  }
              })
              .setTitleColor(Color.DARK_GRAY)
              .setTitleFont(Font.ARIAL_BIG_BOLD)
              .setSubtitle("subtitle")
              .setSubtitleColor(Color.DARK_GRAY)
              .setSubtitleFont(Font.COURIER_NEW_BIG_BOLD)
              .setLegendColor(Color.DARK_GRAY)
              .setLegendFont(Font.COURIER_NEW_MEDIUM_BOLD)
              .setLegendBackgroundColor(Color.WHITE)
              .setLegendPosition(DJChartOptions.EDGE_BOTTOM)
              .setTitlePosition(DJChartOptions.EDGE_TOP)
              .setLineStyle(DJChartOptions.LINE_STYLE_DOTTED)
              .setLineWidth(1)
              .setLineColor(Color.DARK_GRAY)
              .setPadding(5)
              //dataset
              .setCategory((PropertyColumn) columnDestiny)
              .addSerie(columnCount, "Cantidad")
              .addSerie(columnProfit, "Ganancia") // IF I COMMENT THIS LINE THE CHART IS RENDERED
              //plot
              .setCategoryAxisFormat(categoryAxisFormat)
              .setValueAxisFormat(valueAxisFormat)
              .build();
  
      drb.addChart(djChart);
  
      HashMap vars = new HashMap();
      vars.put(columnCount, new JRDesignVariable());
      vars.put(columnProfit, new JRDesignVariable());
      JRDesignGroup group = new JRDesignGroup();
      djChart.transform(new DynamicJasperDesign(), "", group, group, vars, 0);
  
      DynamicReport dr = drb.build();
  
      return dr;
  }
  
  public JasperPrint getJasperPrint(String status, String userOwner,
              String hourFrom, String hourTo, String dateFrom, String dateTo)
          throws ColumnBuilderException, ClassNotFoundException, JRException, ChartBuilderException {
  
      DynamicReport dr = this.buildSalesReport();
  
      JRDataSource ds = new JRBeanCollectionDataSource(
              this.bookService.getReportBooks(status, userOwner, hourFrom, hourTo, dateFrom, dateTo));
  
      return DynamicJasperHelper.generateJasperPrint(dr , new ClassicLayoutManager(), ds);
  }
  
  /**
   *
   * @return
   */
  @SuppressWarnings("serial")
  private CustomExpression getProfitExpression() {
      return new CustomExpression() {
  
          @SuppressWarnings("rawtypes")
          @Override
          public Object evaluate(Map fields, Map variables, Map parameters) {
              Double amount = (Integer)fields.get("count") * (Double)fields.get("bookedObject.price");
              return amount;
          }
  
          @Override
          public String getClassName() {
              return Double.class.getName();
          }
      };
  </code></pre>
  
  <p>As I said, the report is shown properly without the chart, with the chart, it fails only if the expression column is included as a series.</p>
  
  <p>Any ideas are welcomed!</p>