Вероятно, нет способа реализовать желаемое поведение с использованием подотчетов.
Полагаю, что лучший способ сделать это - использовать только группы, но модель данных должна быть немного модифицирована для этого.
Вот мое решение:
public class Test_subReport {
protected static JasperPrint jp;
protected static JasperReport jr;
protected static Map params = new HashMap();
protected static DynamicReport dr;
public static void main(String args[]) throws SQLException, ColumnBuilderException, ClassNotFoundException {
Test_subReport t = new Test_subReport();
t.createReport();
}
public void createReport() throws SQLException, ColumnBuilderException, ClassNotFoundException {
List<DataWrapper> createMockDataset = wrapData(createMockDataset());
Style titleStyle = new Style();
titleStyle.setHorizontalAlign(HorizontalAlign.CENTER);
titleStyle.setFont(Font.ARIAL_SMALL_BOLD);
Style dataStyle = new Style();
dataStyle.setHorizontalAlign(HorizontalAlign.CENTER);
dataStyle.setFont(Font.ARIAL_SMALL);
dataStyle.setBlankWhenNull(true);
final List items = SortUtils.sortCollection(createMockDataset, Arrays.asList(new String[]{"name", "description"}));
FastReportBuilder drb = new FastReportBuilder();
drb.setTemplateFile("templatePortrait.jrxml", true, true, true, true);
drb.addColumn("name", "name", String.class.getName(), 30, dataStyle)
.addColumn("description", "description", String.class.getName(), 100, dataStyle)
.addColumn("id", "id", Integer.class.getName(), 30, dataStyle)
.addColumn("score", "score", Double.class.getName(), 30, false, "$ #.00", dataStyle)
.setTitle("Report")
.setWhenNoDataNoPages()
.setAllowDetailSplit(false)
.setUseFullPageWidth(true);
drb.addGroups(2);
DynamicReport dynamicReport = drb.build();
dynamicReport.setTitleStyle(titleStyle);
HashMap parametros = new HashMap();
parametros.put("dataRelatorio", MyTools.getDataPorExtenso());
doReport(dynamicReport, items, parametros);
}
public void doReport(final DynamicReport _report, final Collection _data, HashMap parametros) {
try {
JRDataSource beanCollectionDataSource = new JRBeanCollectionDataSource(_data);
JasperPrint jasperPrint = DynamicJasperHelper.generateJasperPrint(_report, new ClassicLayoutManager(), beanCollectionDataSource, parametros);
JasperViewer.viewReport(jasperPrint);
} catch (JRException ex) {
ex.printStackTrace();
}
}
public List<DataWrapper> wrapData(List<Fruit> fruits) {
List<DataWrapper> dataList = new ArrayList<>();
for (Fruit fruit : fruits) {
if (fruit.getEvaluations().isEmpty()) {
dataList.add(new DataWrapper(fruit.name, fruit.description, null, null));
} else {
for (Evaluation evaluation : fruit.getEvaluations()) {
dataList.add(new DataWrapper(fruit.name, fruit.description, evaluation.id, evaluation.score));
}
}
}
return dataList;
}
public List<Fruit> createMockDataset() {
ArrayList<Fruit> fruits = new ArrayList<>();
Fruit f1 = new Fruit();
f1.name = "Apple X1";
f1.description = "Yummy yummy apple for the stackoverflow readers 1";
Fruit f2 = new Fruit();
f2.name = "Apple Ag";
f2.description = "Yummy yummy apple for the stackoverflow readers 2";
Fruit f3 = new Fruit();
f3.name = "Apple Mn";
f3.description = "Yummy yummy apple for the stackoverflow readers 3";
Fruit f4 = new Fruit();
f4.name = "Apple O2";
f4.description = "Yummy yummy apple for the stackoverflow readers 4";
//Evaluations for f1
for (int i = 0; i < 4; i++) {
Evaluation e = new Evaluation();
e.id = i;
e.score = Math.random() * 10;
f1.evaluations.add(e);
}
//evaluations for f4
for (int i = 0; i < 4; i++) {
Evaluation e = new Evaluation();
e.id = i;
e.score = Math.random() * 10;
f4.evaluations.add(e);
}
fruits.add(f1);
fruits.add(f2);
fruits.add(f3);
fruits.add(f4);
return fruits;
}
public class Fruit {
public String name;
public String description;
public ArrayList<Evaluation> evaluations = new ArrayList<Evaluation>();
public Fruit() {
}
public Fruit(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public ArrayList<Evaluation> getEvaluations() {
return evaluations;
}
public void setEvaluations(ArrayList<Evaluation> evaluations) {
this.evaluations = evaluations;
}
}
public class Evaluation {
public int id;
public double score;
public Evaluation() {
}
public Evaluation(int id, double score) {
this.id = id;
this.score = score;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}
public class DataWrapper {
public String name;
public String description;
public Integer id;
public Double score;
public DataWrapper() {
}
public DataWrapper(String name, String description, Integer id, Double score) {
this.name = name;
this.description = description;
this.id = id;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
}
}
И вот результат:
Не стесняйтесь спрашивать, если у вас есть какие-либо вопросы.