Multiplicar registros com Ireport [RESOLVIDO]

Estou criando um programa para geração de etiquetas, onde eu preciso multiplicar alguns registros, ou seja eu tenho 1 produto com 10 quantidades por exemplo, onde nas etiquetas ao invés de gerar 1 etiqueta eu preciso gerar 10 pois essa é a quantidade de produtos real, alguém sabe como fazer isso? pode ser por comando SQL ou direto pelo Ireport. Gero meu relatório usando o JRResultSetDataSource

Por que não faz isso no teu backend e manda os dados prontos pro relatório?

Eu pensei nisso, porém acho que para meu caso não é viável, por exemplo o cliente pode querer imprimir 1 produto N vezes, ou seja no meu backend eu teria que duplicar ele N vezes com as mesmas informações só pela quantidade. Eu uso um formulário que exibe os produtos que serão gerados etiquetas para o cliente consultar e verificar se os dados estão corretos.

E qual o problema disso?
Basta você ter um parâmetro que diga qual a quantidade de vias padrão e que possa ser alterado via inteface para que o usuário imprima mais ou menos que aquela quantidade pré definida.

acredito que não vai ser realmente viável para mim porém vou fazer alguns testes, fora isso mais alguma ideia ou por comando SQL ou pelo Ireport?

Você mencionou estar usando JRResultSetDataSource… Trabalho há um bom tempo com relatórios Jasper, mas sempre escrevendo as queries diretamente neles. Mas pesquisando rapidamente entendi que um JRResultSetDataSource recebe um objeto ResultSet, que por sua vez é o resultado da execução de um select no banco.

Bem, uma forma de multiplicar os registros no SQL eu vejo como “chuncho”, porque de certa forma você estaria forçando um produto cartesiano na base.

A alternativa que eu estudaria em seu lugar seria preencher seu relatório com algum tipo de coleção. Esta, por sua vez poderia ser preenchida a partir do ResultSet sendo repetido N vezes num loop simples, onde N você poderia receber por parâmetro informado pelo usotário.

Concordo com o @Ademiltonjlc.
Uma possibildiade seria criar 10 bands details e colocar 1 registro por detail.
Lógico que isso não seria interessante, devido ao que você mesmo colocou, a necessidade de customizar a quantidade de etiquetas.
De qualquer forma, deixar de lado o jrresultsetdatasource seria a melhor solução.

@Ademiltonjlc de que forma você costuma gerar seus relatórios pelo ireport? eu faço dessa forma pois achei muito simples e sempre consegui fazer tudo que gostaria e precisava com ela, só agora que esbarrei nessa barreira. Tentei fazer usando procedures porém sem sucesso, pelo que pesquisei o ireport não dá suporte para procedures em mysql, estou pensando agora em criar um array de objetos, povoar ele e gerar meu relatório a partir deste array.

O @Ademiltonjlc eu não sei, mas eu utlizo o padrão MVC e nunca coloco a view em contato direto com o model.
Por isso, o ideal é você utilizar o JRBeanCollectionDatasource…

@Luis_Augusto_Santos vou dar uma pesquisada sobre JRBeanCollectionDatasource, você acha que a ideia de passar um array para ireport é valida também?

Padrões de desenvolvimento à parte(pelos quais tenho o devido respeito) desenvolvo meus reports escrevendo os selects diretamente dentro deles. Em desenvolvimento seto uma conexão com o banco e “pau no gato”. Em runtime, ao renderizar o report, no método JasperFillManager.fillReport() passo um objeto Connection e o resto acontece.
É uma aplicação desktop e esse cenário nunca me trouxe problemas. Quando sugeri “coleções” para solucionar seu caso não tinha nada específico em mente, mas de repente essa dica do Luis_Augusto_Santos pode mesmo ser o tiro de misericórdia aí.
Poste seus progressos e dúvidas, está um post interessante esse.

@Luis_Augusto_Santos e @Ademiltonjlc vou passar o dia testando estas possibilidades levantadas, agradeço desde já a ajuda, se vocês puderem e tiverem poderiam me encaminhar algum exemplo de código ou links úteis seria de grande ajuda, qualquer evolução postarei no tópico, obrigado.

Consegui evoluir, segue classe que chamou para a impressão

private void btnImprimirMouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
EtiquetaProdutosDAO eDAO = new EtiquetaProdutosDAO();
ArrayList etiquetas = new ArrayList();
JDialog viewer;
String caminho;
JasperDesign design;
JasperReport etiqueta;
JRDataSource jrds;
JasperPrint jp;
JasperViewer jv;

    try {
        etiquetas = eDAO.imprimir();            
        if (etiquetas.size() > 0) {
            //CRIA JDIALOG, DEVIDO AO PROBLEMA DO IREPORT ABRIR ATRÁS DO JDIALOG
            //OU SEJA FOI NECESSÁRIO INSERIR O IREPORT DENTRO DO JDIALOG PARA SOLUCIONAR
            viewer = new JDialog(new javax.swing.JFrame(), "RELATÓRIO", true);
            viewer.setBounds(GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds());
            viewer.setLocationRelativeTo(null);
            
            //PEGA CAMINHO DO RELATÓRIO
            caminho = new File("src/br/com/report/etiqueta1.jrxml").getAbsolutePath();
            
            //ALTERA RELATÓRIO EM TEMPO DE EXECUÇÃO COM AS CORDENADAS DE IMPRESSÃO DA ETIQUETA
            design = JRXmlLoader.load(caminho);
            design.setLeftMargin(1);
            etiqueta = JasperCompileManager.compileReport(design);
            
            //PASSA ARRAY PARA BEAN E FINALIZA PASSOS PARA IMPRESSÃO DO RELATÓRIO
            jrds = new JRBeanCollectionDataSource(etiquetas);
            jp = JasperFillManager.fillReport(etiqueta, null, jrds);
            jv = new JasperViewer(jp, false);
            
            viewer.getContentPane().add(jv.getContentPane());
            viewer.setVisible(true);
        } else {
            
        }            
    } catch (HeadlessException | JRException e) {
        Logger.getLogger(Etiquetas.class.getName()).log(Level.SEVERE, null, e);
    }                       
}

O Array está sendo preenchido da forma como eu precisava e está retornando de forma correta, porém quando chega na linha “jp = JasperFillManager.fillReport(etiqueta, null, jrds);” ele me retorna uma exceção:

GRAVE: null
net.sf.jasperreports.engine.JRException: Error retrieving field value from bean :
at net.sf.jasperreports.engine.data.JRAbstractBeanDataSource.getBeanProperty(JRAbstractBeanDataSource.java:123)
at net.sf.jasperreports.engine.data.JRAbstractBeanDataSource.getFieldValue(JRAbstractBeanDataSource.java:96)
at net.sf.jasperreports.engine.data.JRBeanCollectionDataSource.getFieldValue(JRBeanCollectionDataSource.java:109)
at net.sf.jasperreports.engine.fill.JRFillDataset.setOldValues(JRFillDataset.java:1358)
at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:1259)
at net.sf.jasperreports.engine.fill.JRFillDataset.next(JRFillDataset.java:1235)
at net.sf.jasperreports.engine.fill.JRBaseFiller.next(JRBaseFiller.java:1614)
at net.sf.jasperreports.engine.fill.JRHorizontalFiller.fillReport(JRHorizontalFiller.java:155)
at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:963)
at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:892)
at net.sf.jasperreports.engine.fill.JRFiller.fill(JRFiller.java:114)
at net.sf.jasperreports.engine.JasperFillManager.fill(JasperFillManager.java:668)
at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:984)
at br.com.odbo.ui.Etiquetas.btnImprimirMouseClicked(Etiquetas.java:615)
at br.com.odbo.ui.Etiquetas.access$1400(Etiquetas.java:53)
at br.com.odbo.ui.Etiquetas$11.mouseClicked(Etiquetas.java:346)
at java.awt.Component.processMouseEvent(Component.java:6536)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3324)
at java.awt.Component.processEvent(Component.java:6298)
at java.awt.Container.processEvent(Container.java:2236)
at java.awt.Component.dispatchEventImpl(Component.java:4889)
at java.awt.Container.dispatchEventImpl(Container.java:2294)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4888)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4534)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4466)
at java.awt.Container.dispatchEventImpl(Container.java:2280)
at java.awt.Window.dispatchEventImpl(Window.java:2746)
at java.awt.Component.dispatchEvent(Component.java:4711)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:758)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86)
at java.awt.EventQueue$4.run(EventQueue.java:731)
at java.awt.EventQueue$4.run(EventQueue.java:729)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:109)
at java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:184)
at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:229)
at java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:227)
at java.security.AccessController.doPrivileged(Native Method)
at java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:227)
at java.awt.Dialog.show(Dialog.java:1084)
at java.awt.Component.show(Component.java:1671)
at java.awt.Component.setVisible(Component.java:1623)
at java.awt.Window.setVisible(Window.java:1014)
at java.awt.Dialog.setVisible(Dialog.java:1005)
at br.com.odbo.ui.Etiquetas$14.run(Etiquetas.java:707)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:311)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:756)
at java.awt.EventQueue.access$500(EventQueue.java:97)
at java.awt.EventQueue$3.run(EventQueue.java:709)
at java.awt.EventQueue$3.run(EventQueue.java:703)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:726)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.lang.NoSuchMethodException: Unknown property ‘’ on class 'class [Ljava.lang.Object;'
at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1322)
at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:770)
at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:846)
at org.apache.commons.beanutils.PropertyUtils.getProperty(PropertyUtils.java:426)
at net.sf.jasperreports.engine.data.JRAbstractBeanDataSource.getBeanProperty(JRAbstractBeanDataSource.java:111)
… 68 more

Opa parabéns pelos progressos. Se ainda quiser olhar abordagens diferentes, veja isso:

(esse está parecido com o que voccê fez, mas repare no passo de compilação do jrxml que ele faz diferente:
http://www.k19.com.br/artigos/relatorios-em-java-jasperreports-e-irepor/

Esse outro tem mais exemplos, inclusive usando sql dentro dele, como eu disse que faço:

https://pablonobrega.wordpress.com/2009/02/11/tutorial-tecnicas-de-geracao-de-relatorios-com-jasperreports/

Este tipo de exceção está ligado à tentativa de obter o valor pré definido para um field que não consta no bean que representa cada linha de dados.
Pode ser erro na grafia ou a ausência do método getter respectivo.

Consegui progredir mais … o erro Error retrieving field value from bean estava dando pois eu não estava trabalhando com getters e setters da minha classe, eu simplesmente pegava o resultado vindo do resultset e passava para meu ArrayList como objeto, ou seja ele nunca encontrava o campo e sempre o objeto em si.

Após isso passei por outro erro java.lang.NoSuchMethodException: Unknown property '', depois de muito quebrar a cabeça e vasculhar a internet achei uma solução simples, apenas inserir um parametro false na chamada da função jp = JasperFillManager.fillReport(etiqueta, null, new JRBeanCollectionDataSource(etiquetas, false)); esse link me ajudou muito http://miguellimapj.blogspot.com.br/2013/01/javalangnosuchmethodexception-do-ireport.html

Agora estou conseguindo receber meu ArrayList de forma correta e consigo imprimir ele porém o que acontece, antes minha chamada do Array era feita da seguinte forma:

etiquetas.add(new Object[]{                             
                        rs.getString("CODIGOBARRAS"),
                        rs.getString("PRODUTO"),
                        rs.getDouble("PRECO"),
                        rs.getInt("QTDE")});

Agora é assim:

epDTO.setCodigobarras(rs.getString(“codigobarras”));
epDTO.setProduto(rs.getString(“produto”));
epDTO.setPreco(rs.getDouble(“preco”));
epDTO.setQtde(rs.getInt(“qtde”));
etiquetas.add(epDTO);

No primeiro caso para cada dado vindo do meu ResultSet eu criava uma posição nova e preenchia com os dados de forma correta, já no segundo caso independentemente do números de produtos diferentes que eu possuo sempre ele me retorna todas as posições com o preenchimento dos dados do ultimo registro, ou seja ele me retorna sempre um ArrayList de produtos iguais. O que posso fazer para solucionar isso?

CONSEGUI finalmente, como eu disse acima sempre que eu preenchia meu array ele pegava a ultima posição e todos os produtos ficavam iguais a da ultima, eu imagino que isso ocorra porque o endereço na memória é o mesmo, ou seja ele na verdade não é alterado e sim sobreposto.

public ArrayList imprimir() {
Connection con = null;
PreparedStatement ps = null;
ResultSet rs = null;
String comandoSQL = “”;
ArrayList etiquetas = new ArrayList();

    try {
        con = Conexao.abrir();
        comandoSQL = "SELECT codigobarras, produto, preco, qtde FROM etiquetasprodutos";
        ps = con.prepareStatement(comandoSQL);
        rs = ps.executeQuery();
                    
        if (rs.next()) {
            do {
                EtiquetaProdutosDTO epDTO = new EtiquetaProdutosDTO();
                
                if (rs.getInt("qtde") > 1) {
                    for (int i = 0; i < rs.getInt("qtde"); i++) {
                        epDTO.setCodigobarras(rs.getString("codigobarras"));
                        epDTO.setProduto(rs.getString("produto"));
                        epDTO.setPreco(rs.getDouble("preco"));
                        epDTO.setQtde(rs.getInt("qtde"));
                        etiquetas.add(epDTO);
                    }
                } else {
                    epDTO.setCodigobarras(rs.getString("codigobarras"));
                    epDTO.setProduto(rs.getString("produto"));
                    epDTO.setPreco(rs.getDouble("preco"));
                    epDTO.setQtde(rs.getInt("qtde"));
                    etiquetas.add(epDTO);
                }
                                    
            } while (rs.next());
        }
    } catch (SQLException | ClassNotFoundException e) {
        Logger.getLogger(EtiquetaProdutosDAO.class.getName()).log(Level.SEVERE, null, e);
    }
    return etiquetas;
}  

Resolvi da seguinte maneira, eu criava meu objeto antes do try ou seja ele sempre era o mesmo no endereço de memória, coloquei ele no meu laço de repetição do while e a partir disse ele é criado sempre para cada item do meu array ou seja, endereço de memória diferente, assim cada elemento em uma posição diferente. Não sei se fiz da melhor forma e se estou correto no que acabei de falar, porém pelo que consegui analisar cheguei nessa conclusão e a resolução do problema. @Ademiltonjlc e @Luis_Augusto_Santos muito obrigado pelo tempo, paciência e as dicas, elas foram essenciais para que eu resolvesse o problema.

Olá.
Isso está com cara de que você tenha criado o objeto epDTO somente uma vez e dentro do loop que percorres o resultset estás usando o mesmo objeto para atribuir os valores. Precisas criar um novo objeto para cada registro que passar, daí seta os valores e o adiciona na coleção

Mais um X atrás da porta e um bom post pra galera