JasperReports空数据列表时添加对应类型对象避免空白PDF
解决JasperReports空列表生成空白PDF的问题
我完全懂你的需求——不想让空列表输出空白PDF,而是自动填一个对应类型的空对象进去。下面就一步步帮你实现:
首先,核心问题是在运行时获取List的元素类型,然后通过反射创建这个类型的实例并添加到空列表里。因为Java泛型有类型擦除,直接拿data.getClass()只能得到List,得通过反射获取泛型的实际类型参数。
具体修改步骤
添加获取元素类型的工具方法
在你的类里新增一个私有方法,用来解析List的泛型元素类型:private Class<?> getListElementType(List<?> data) throws IllegalArgumentException { Type genericType = data.getClass().getGenericSuperclass(); // 检查是否是参数化类型(即带有泛型信息的List) if (!(genericType instanceof ParameterizedType)) { throw new IllegalArgumentException("无法确定List的元素类型,请确保传入的List带有泛型信息"); } ParameterizedType paramType = (ParameterizedType) genericType; // 获取List<T>中的第一个类型参数T Type elementType = paramType.getActualTypeArguments()[0]; // 转换为Class对象 if (elementType instanceof Class<?>) { return (Class<?>) elementType; } else { throw new IllegalArgumentException("无法解析List的元素类型"); } }在gerarJasper方法中处理空列表
在你标注的位置(// here I would like to know what the Object Type of the data parameter)加入以下逻辑:// 处理空列表:添加对应类型的空对象 if (data != null && data.isEmpty()) { try { Class<?> elementClass = getListElementType(data); // 通过反射创建无参构造的实例 Object emptyInstance = elementClass.getDeclaredConstructor().newInstance(); data.add(emptyInstance); } catch (NoSuchMethodException e) { throw new FacesException("目标类没有无参构造器:" + e.getMessage(), e); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new FacesException("创建空实例失败:" + e.getMessage(), e); } }注意事项
- 确保你的实体类(比如
TrUltimaLocalizacaoGps)存在无参构造器,否则反射创建实例会失败。如果实体类只有带参构造,你需要修改反射逻辑来适配带参构造(比如传入默认值)。 - 如果传入的List是没有泛型信息的原始类型(比如
new ArrayList()而不是new ArrayList<TrUltimaLocalizacaoGps>()),上面的方法会抛出异常,这种情况建议在调用gerarJasper时强制使用带泛型的List。
- 确保你的实体类(比如
修改后的关键代码片段
(只展示修改部分,其余代码保持不变)
public void gerarJasper(String jasperName, String type, List data, Map params) throws IllegalArgumentException, RuntimeException, Exception { // 原有代码省略... FacesContext fc = FacesContext.getCurrentInstance(); ServletContext context = (ServletContext)fc.getExternalContext().getContext(); String path = context.getRealPath(File.separator) + "resources/jasper" + File.separator; params.put("SUBREPORT_DIR", path); // ======== 新增的空列表处理逻辑 ======== if (data != null && data.isEmpty()) { try { Class<?> elementClass = getListElementType(data); Object emptyInstance = elementClass.getDeclaredConstructor().newInstance(); data.add(emptyInstance); } catch (NoSuchMethodException e) { throw new FacesException("目标类没有无参构造器:" + e.getMessage(), e); } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { throw new FacesException("创建空实例失败:" + e.getMessage(), e); } } // ==================================== JRDataSource ds = new JRBeanArrayDataSource(data.toArray()); // 后续原有代码省略... } // 新增的工具方法 private Class<?> getListElementType(List<?> data) throws IllegalArgumentException { Type genericType = data.getClass().getGenericSuperclass(); if (!(genericType instanceof ParameterizedType)) { throw new IllegalArgumentException("无法确定List的元素类型,请确保传入的List带有泛型信息"); } ParameterizedType paramType = (ParameterizedType) genericType; Type elementType = paramType.getActualTypeArguments()[0]; if (elementType instanceof Class<?>) { return (Class<?>) elementType; } else { throw new IllegalArgumentException("无法解析List的元素类型"); } }
另外注意到你原有代码里的一个小问题:InputStream stream = econtext.getResourceAsStream(PREFIX + name + SUFFIX);这里的name应该是方法参数jasperName,否则会出现变量未定义的错误,我在代码片段里已经修正了这个问题。
这样修改后,当传入的List为空时,就会自动创建一个对应类型的空对象添加进去,JasperReports就能正常生成带空数据行的报表,而不是空白PDF了。
内容的提问来源于stack exchange,提问作者Gustavo Menezes
相关产品推荐
相关产品推荐

