IReport - Subreport - Lista dentro de Lista usando JRBeanCollectionDataSource [RESOLVIDO]

Olá a todos…

Pessoal estou criando um relatório que possui um subreport.
Basicamente eu tenho uma lista de objetos e em cada objeto eu tenho uma outra lista de objetos.

Vejam o código:

List<BeneficiarioTO> listaBeneficiarios = bo.findAllConsumoMensalBenefiario("32362", "2009-09-01");
		
for(BeneficiarioTO toAux : listaBeneficiarios){
	List<ExtratoTO> listaExtratos = bo.findAllExtradoUtilizacaoBenefiario("32362", "2009-09-01");
	toAux.setListaExtratos(listaExtratos);
}
		
JRBeanCollectionDataSource beanDataSource = new JRBeanCollectionDataSource(listaBeneficiarios);
		
//Parâmetros do relatório - Nao passo nenhum
Map parametros = new HashMap();

String arquivo = "C:/Trabalhos/projetos/portalrh/WebContent/relatorios/relatorioExtratoBeneficiario.jasper";
		
JasperPrint reportToPrint = JasperFillManager.fillReport(arquivo, parametros, beanDataSource); 
        

No meu relatório pricipal eu tenho 3 filds : nome (do tipo String), matrícula (do tipo String) e listaExtratos (do tipo java.util.List).
No meu subreport eu coloquei apenas um fild que é do tipo String e coloquei o connection type como “use datasource expression” e em Data Source Expression eu coloquei $F{listaExtratos}.

Quando eu rodo o relatório acontede o seguinte erro:

Exception in thread "main" net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression : 
	Source text : $F{listaExtratos}

Alguêm sabe o motivo do erro?

Obrigado.

Isso ocorre na hora de compilar seu relatório?

O erro ocorre quando eu executo o relatório.

Pessola consegui!!! :lol:

Segue a solução:

A minha classe BeneficiarioTO possui os seguintes atribusto:

private String matricula;
private String nome;
List<ExtratoTO> listaExtratos;

No IReport eu mapiei os dois primeiro com String e o atributo listaExtratos como java.util.List.

Agora o pulo do gato: Inseri o subreport e coloquei as seguintes propriedades:

connection type: use datasource
data souce expression: new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{listaExtratos})

No subrepostes eu coloquei os atritutos contidos no meu objeto ExtratoTO com os mesmo data types.

E funcionou! :lol:

Obrigado e um abraço para todos.

Olá warley, cara, revivendo este seu post, estou conseguindo gerar o relatorio seguindo o que vc passou neste post, so não to conseguindo pegar dinamicamente o subrelatorio para exibição, quando seto na mão o caminho absoluto do arquivo ai funciona legal, mas quando tento por o contexto da minha aplicação web ele não encontra o .jasper e ele esta la sim.

Como vc fez pra pegar dinamicamente o subrelatorio???

[]'s

Pelo que eu pude entender você quer pegar o Jasper pelo contexto, pegar o path dele e mandar pro relatório principal. É isso? Se for isso, você pode criar um parâmetro dentro do relatório, colocar esse parâmetro como caminho pro subrelatório e, quando for executar a aplicação, pegar no contexto, obter o path e setar o parâmetro.

Olá Andre, mesmo eu setando manualmente ou pegando o contexto pelo faces, ele não consegue achar o subrelatorio, e sim eu estou passando o caminho dele por um parametro do relatorio principal, o que é estranho pois o sub relatorio esta no mesmo diretorio que o relatorio principal (/meuContexto/relatorios) e este é encontrado na pasta do contexto normalmente. E para o subrelatorio eu estou tendo de setar o caminho absoluto da pasta que contem o arquivo.

Obrigado pela ajuda!

[]'s

Humm… Estranho.
Se o sub está na mesma pasta em que o relatório principal, você só precisa colocar o nome do Jasper no parâmetro (no próprio iReport mesmo). Dá uma olhada se ele muda no XML isso também… Eu fiz algumas vezes e passei algumas horas até descobrir que não estava alterando no xml.

No ireport eu utilizo um parametro que passa o caminho do subrelatorio, acho q é o padrão do ireport quando vc cria um subrelatorio, pois ele mesmo criou esse parametro pra mim quando criei o subrelatorio. Quanto ao “xml” que vc se refere seria o “.jrxml” ???

Mais uma vez obrigado pela ajuda!

[]'s

Sim, o jrxml.
Se todos estiver em /home/user/app/reports (todos os jaspers, eu quero dizer), no seu relatório só deve ter o nome dos subrelatórios. Mais nada. Não precisa de parâmetro, nem nada. Você só precisa usar parâmetros quando os reports estão em lugares diferentes (ou podem mudar… quando você coloca num ear, por exemplo).

Revivendo novamente…

No relatorio principal, vc falou q colocou FIELDS né… Mas assim, vc alimentou esse fields como ?
Pq se vc não colocar uma fonte de dado, ele não compila
ele fala assim:
Field not found: “nomeDoField”

Tentei trocar. No lugar de TextField, eu coloquei Parameters. Assim no Ireport ele compila, mas o relatorio fica todo em branco quando executo a aplicação.

Tem com vc me ajudar?

abraço.

Olá Lazaro, os Fields são realmente necessarios pois eles representam a sua coleção que estiver sendo passada ao relatorio em tempo de execução, talves o que possa estar acontecendo é vc estar inserindo um field não declarado no seu relatorio, ou mesmo se for em tempo de execução em sua coleção o objeto que estiver sendo passado deve possuir uma correspondencia entre cada field e uma propriedade de seu objeto.

[]'s

Mas velho… se eu colocar o field na mão, o Ireport não gera o .jasper

E estou passo o .jasper pro aplicação…

Devo então passar o .jrxml e mandar ele compilar o jasper??

daí ele vai pegar o field e atriduir ao campo nome da minha classe…

será q é isso ?

Lazaro, vc esta utilizando o ireport certo?
Voce consegue compilar e rodar a partir de sua aplicação sem adicionar o subrelatorio? Isto usando o Field?

Vamos tentar eliminar as coisas aos poucos…rsrsrs

[]'s

Não consigo, pois passo para a minha aplicação o .jasper

E se eu coloco no Ireport, os fields e tento compilar para gerar o jasper ele fala q o field não foi encontrado…

=/

Bom, vamos voltar mais um pouquinho:

1º. vc ja utilizou o jasper / ireport antes, tem um bom conhecimento de como criar relatorios com ele?

2º. vc ja verificou se seu objeto que esta sendo passado para o relatorio atraves do seu JRBeanCollectionDataSource tem as propriedades iguais as declaradas no seu relatorio (nome atributo = nome do field no caso)

Sei que podem parecer bobas estas perguntas, mas fica dificil achar um erro sem conhecer realmente seu problema, pois no erro q vc passou ele da a impressão que ele não esta encontrando uma correspondencia entre a field e seu objeto.

[quote=thiagocg]Bom, vamos voltar mais um pouquinho:

1º. vc ja utilizou o jasper / ireport antes, tem um bom conhecimento de como criar relatorios com ele?

2º. vc ja verificou se seu objeto que esta sendo passado para o relatorio atraves do seu JRBeanCollectionDataSource tem as propriedades iguais as declaradas no seu relatorio (nome atributo = nome do field no caso)

Sei que podem parecer bobas estas perguntas, mas fica dificil achar um erro sem conhecer realmente seu problema, pois no erro q vc passou ele da a impressão que ele não esta encontrando uma correspondencia entre a field e seu objeto.

[/quote]

Então Tiago

1º Já utilizei o Jasper / Ireport antes, mas era tudo versão antiga. Agora estou usando tudo novo.

2º Já verifiquei isso sim.
Coloquei no ireport “$F{nome}”, “$F{dependentes}”.
Na minha classe Java eu tenho: “protected String nome;” e “protected List dependentes;”

Vou postar meu codigo aki

public class Main {

	private static final String CAMINHO_PDF = "C:\\AMBIENTE SISOUVIDOR\\RELATORIO\\relatorio.pdf";
//	private static final String CAMINHO_JASPER = "C:\\AMBIENTE SISOUVIDOR\\RELATORIO\\report1.jasper";
	private static final String CAMINHO_JRXML = "C:\\AMBIENTE SISOUVIDOR\\RELATORIO\\report1.jrxml";
	public static void main(String[] args) throws Exception {
		ClienteDao clienteDao = new ClienteDao();
		List<Cliente> clientes = montarDados(clienteDao);
		
		limparPasta();
		JasperPrint montarRelatorio = montarRelatorio(clientes);
		gerarRelatorio(montarRelatorio);
		System.out.println(" fim ");
	}

	private static void limparPasta() {
		File file = new File(CAMINHO_PDF);
		if(file.exists())
			file.delete();
	}

	private static void gerarRelatorio(JasperPrint reportToPrint) throws JRException, IOException {
		File f = new File(CAMINHO_PDF);
		byte[] bytes = JasperExportManager.exportReportToPdf(reportToPrint);
		FileOutputStream out = new FileOutputStream(f);
		out.write(bytes);
	}

	@SuppressWarnings("unchecked")
	private static JasperPrint montarRelatorio(List<Cliente> clientes) throws JRException, FileNotFoundException {
		JRBeanCollectionDataSource beanDataSource = new JRBeanCollectionDataSource(clientes);
		Map parametros = new HashMap();		
		JasperDesign design = JRXmlLoader.load(CAMINHO_JRXML);
		JasperReport report = JasperCompileManager.compileReport(design);
		return JasperFillManager.fillReport(report,parametros, beanDataSource);
	}

	@SuppressWarnings("unchecked")
	private static List<Cliente> montarDados(GenericDao<?> dao)
			throws Exception {
		List<Cliente> lista = (List<Cliente>) dao.list();
		for (Cliente clienteAux : lista) {
			clienteAux.getDependentes();
		}
		return lista;
	}

}

o erro é:

Exception in thread "main" net.sf.jasperreports.engine.design.JRValidationException: Report design not valid : 
	 1. Field not found : nome
	 2. Field not found : dependentes
	 3. Field not found : dependentes
	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 br.com.netx.prototipo.relatorio.Main.montarRelatorio(Main.java:57)
	at br.com.netx.prototipo.relatorio.Main.main(Main.java:34)

E muito obrigado pela atenção.

private static List<Cliente> montarDados(GenericDao<?> dao) throws Exception { List<Cliente> lista = (List<Cliente>) dao.list(); for (Cliente clienteAux : lista) { clienteAux.getDependentes(); } return lista; }
1º. No seu metodo getDependentes() vc ta atribuindo os dependentes que retornam a sua lista que esta sendo retornada para o metodo de construção do JRBeanCollectionDataSource? Pois aparentemente vc esta pegando os dependentes mas não esta atribuindo a nada.

2º. O seu objeto cliente tem um um atributo nome e um metodo publico getNome() ???

3º. Faz um print do seu relatorio do jasper mostrando o relatorio e os fields declarados pra eu dar uma olhada.

[]'s

[quote=thiagocg] private static List<Cliente> montarDados(GenericDao<?> dao) throws Exception { List<Cliente> lista = (List<Cliente>) dao.list(); for (Cliente clienteAux : lista) { clienteAux.getDependentes(); } return lista; }
1º. No seu metodo getDependentes() vc ta atribuindo os dependentes que retornam a sua lista que esta sendo retornada para o metodo de construção do JRBeanCollectionDataSource? Pois aparentemente vc esta pegando os dependentes mas não esta atribuindo a nada.

2º. O seu objeto cliente tem um um atributo nome e um metodo publico getNome() ???

3º. Faz um print do seu relatorio do jasper mostrando o relatorio e os fields declarados pra eu dar uma olhada.

[]'s[/quote]

Vamos lá…

1º Fiz um debbuger nessa lista aí. E ele está retornando a lista sim… Completa, com o objeto CLiente e seus respectivos dependentes. Daí eu passei essa lista pro JRBeanCollectionDataSource:

private static JasperPrint montarRelatorio(List<Cliente> clientes) throws JRException, FileNotFoundException {
		JRBeanCollectionDataSource beanDataSource = new JRBeanCollectionDataSource(clientes);

Nessa lista, eu tenho o objeto CLiente e dentro dela varios Dependentes. Isso está correto né?

2º Meu objeto tem sim o get e o set do atributo nome:

public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}

3º QUer um print do Ireport?

Abraço

esse field dependentes ai no seu relatorio não vai funcionar, ele tem q ser passado para o subrelatorio conforme o 4º post desta discussão, como segue abaixo:

[quote]A minha classe BeneficiarioTO possui os seguintes atribusto:

private String matricula;
private String nome;
List listaExtratos;

No IReport eu mapiei os dois primeiro com String e o atributo listaExtratos como java.util.List.

Agora o pulo do gato: Inseri o subreport e coloquei as seguintes propriedades:

connection type: use datasource
data souce expression: new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{listaExtratos})

No subrepostes eu coloquei os atritutos contidos no meu objeto ExtratoTO com os mesmo data types. [/quote]

So seguir isso q vai funcionar.

[]'s