Jump to content
Changes to the Jaspersoft community edition download ×

custom JRIncrementer


canistel

Recommended Posts

Hi, I am trying to do something which is fairly simple... I want an average field on my report, but I don't want to include the field value if (at that point in time) the field value is zero; I only want the average to be affected by values greater then zero.

 

The only way I am aware of to do this is to create a custom JRIncrementer... I've been playing around with this now for a whole day but I just can't seem to make it work; I am sure I am making it more difficult then it needs to be, but can somebody help me out here?

 

I am using ireport, and I set the Custom Incrementor Factory class to "NonZeroAvgIncrementer", and I know that works, it's just that the class is calculating it wrong. Here is my class; I created an internal class called "Average" to hold the state of each avg field that this class is calculating as I have multiple avg fields on the same report, but I am sure that is overkill as well. Please ignore my custom debugging statements...

 

EDIT: I should also mention that it appears to be throwing the calculation in that the last line item is entered twice so thereby affecting the average calcualtion twice and not once like it should.

 

Code:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.fill.AbstractValueProvider;
import net.sf.jasperreports.engine.fill.JRFillVariable;
import net.sf.jasperreports.engine.fill.JRIncrementer;

public class NonZeroAvgIncrementer implements net.sf.jasperreports.engine.fill.JRIncrementerFactory, net.sf.jasperreports.engine.fill.JRIncrementer {
private List<Average> state = new ArrayList<Average>();

public Object increment(JRFillVariable var, Object val, AbstractValueProvider arg2) throws JRException {
Average avg;
double d;


if (var.isInitialized()) return new Double(0);
// if (var.getName().equals("avgFM"«»)){
// System.out.println("break"«»);
// System.out.println(var.getEstimatedValue());
// }//if
avg = findOrCreate(var.getName());
if (var.getIncrementedValue() == null){
avg.reset();
// System.out.println("reset: " + var.getName());
} else {
// System.out.println(var.getIncrementedValue() + ": " + var.getName());
}//if
d = JasperUtil.cdbl(val);
avg.add(d);
d = avg.average();
var.setIncrementedValue(JasperUtil.cdbl(val));
var.setValue(d);
return d;
}//increment

private Average findOrCreate(String name){
int index;
Average avg;

avg = new Average(name);
index = Collections.binarySearch(state, avg);
if (index < 0){
System.out.println("avg not found, creating new: " + name);
state.add(avg);
Collections.sort(state);
return avg;
}//if
return state.get(index);
}//findOrCreate


public JRIncrementer getIncrementer(byte arg0) {
return this;
}//getIncrementer

public class Average implements Comparable<Average>{
private String name;
private double total;
private int count;

public Average(String name){
this.name = name;
reset();
}//Average

public void reset(){
boolean reset;

if (total > 0 | count > 0) reset = true; else reset = false;
total = 0;
count = 0;
if (name.equals("avgFM"«») & reset) out("reset: " + name);
}//reset

public void add(double amt){
if (amt >= 0.01){
total += amt;
count++;
if (name.equals("avgFM"«»)) out(name + ": " + count + " " + amt + " " + total);
}//if
}//add

public double average(){
double d;

d = (double)((double)total / (double)count);
if (name.equals("avgFM"«»)) out("avgFM: avg = " + d);
return d;
}//average

public int compareTo(Average o) {
return name.compareTo(o.name);
}//compareTo

private void out(String s){
System.out.println(s);
}//out
}//Average

}//NonZeroIncrementer

Post edited by: canistel, at: 2008/01/12 01:41

Link to comment
Share on other sites

  • Replies 1
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

canistel wrote:

Hi, I am trying to do something which is fairly simple... I want an average field on my report, but I don't want to include the field value if (at that point in time) the field value is zero; I only want the average to be affected by values greater then zero.

 

You should try to take advantage of the fact that the built-in average incrementer ignores null values. You would do so by using a variable expression that produces null for zero values:

Code:

<variable name="averageVar" class="java.lang.Double" calculation="Average">
<variableExpression>$F{data}.doubleValue() <= 0d ? null : $F{data}</variableExpression>
</variable>

 

HTH,

Lucian

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...