JRimum - Novo projeto open source brasileiro

[quote=cmoscoso][quote=Romulinho]Lançado no dia 15/06/2008 o JRimum, um novo projeto brasileiro que objetiva a criação de componentes reutilizáveis Java com foco no domínio de negócios do Brasil.

O projeto começa com o Bopepo, a biblioteca para geração de boletos bancários que traz algumas inovações, principalmente no quesito personalização.

Confiram o site do projeto e apóiem esta mais nova iniciativa Potiguar!!![/quote]

Me parece esse um projeto com o mesmo proposito do Caelum Stela, é isso mesmo?

[/quote]

Procuramos criar componentes os mais reutilizáveis possíveis, tentar construir uma Linguagem ubíqua para o domínio brasileiro. Exemplo, se eu quero reunir as características de CPF e CNPJ em uma classe ou interface como devo chamá-la? Optamos por CPRF (Cadastro de Pessoas na Receita Federal), e por aí vai.

Segundo o site do Stella e pelo projeto:

O Caelum Stella visa suprir as necessidades comumente encontradas em aplicações desenvolvidas para o mercado brasileiro. Atualmente, o Caelum Stella fornece uma biblioteca de validadores, formatadores e conversores para documentos brasileiros, tais como CPF, CNPJ e PIS/PASEP; além de um gerador de boletos bancários.

Achamos que foge do que queremos para nosso ativo de software, queremos componentes desenhados em um estilo DDD e não só validadores e conversores. Mas isso é uma opção nossa, o projeto deles é muito bom, achamos que é mais uma questão de requisitos mesmo e de termos um planejamento a longo prazo diferente.

[quote=sergiotaborda]Finalmente uma coisa feita com pés-e-cabeça.

Interessante que pessoa tenha addRG e RG tenha getPessoa. Isso é realmente correto no Brasil já que uma pessoa pode ter realmente mais do que um RG ( aposto que a maioria não sabia disso)

O uso de “small data types” também é interessante.

O que eu achei engraçado foi ter pessoa.getSexo() mas não retorna MUITO ou POUCO lol
retorna EnumSexo (F ou M). Aqui teve uma certa gambiarrada… seria mais claro

Pessoa.getSexo()

Sexo.FEMENINO
Sexo.MASCULINO

Não é necessário escrever “Enum” no nome da classe. E as boas praticas apontam que é um falha usar abreviaturas em constantes… tlv o problema é que fica meio feio escreve Sexo.FEMENINO, mas isso é porque a palavra certa seria Genero.
Ai fica mais bonito, é um português mais correto e menos “constangedor”.

mas tudo bem… pelo menos dá para ver que o design foi pensado e que ha tentativa de seguir normas externas.

[/quote]

Para a versão bopepo-incubada nosso foco foi principalmente nos requisitos “boleto”, mas alertamos no site que mudanças no design das classes podem ocorrer e ,sempre é provável que ocorram. Principalmente quando se trata de uma versão de tipo incubada. Em relação ao tipo Sexo: Gênero realmente é bem melhor, grande observação, quase nunca lembramos de “Gêneros”.

[quote=velo]Essa iniciativa é relacionada de alguma forma com o antigo BrasUtils (foi desenvolvido aqui, pela galera do forum)?

VELO[/quote]

Não, mas acho que essa coisa de (BrasilUtils) deve existir na mente de todo desenvolvedor do Brasil, por isso estamos procurando realmente fazer pelo menos um componente que seja razoavelmente reusável, e não, ter utilitários que serve para poucos.

Oi Gilmar!

Iamos criar as classes de dominio (CPF, CNPJ, etc). optamos por nao cria-las para nao forcar a pessoa a usar nosso dominio, mas ai devido a sugestoes iamos cria-las e deixa-las opcionais. Quem sabe podemos trabalhar em conjunto.

[quote=sergiotaborda][quote=Romulinho]Bom galera! Obrigado pelas opiniões…

Mas é isso mesmo que a gente tava procurando, FEEDBACK.
(…)
Quanto ao “Enum”, a gente ta tentando estabelecer um padrão pra nomenclaturas, mas que também está em processo de amadurecimento.

[/quote]

Vc não cria classes chamadas ClassCliente nem InterfaceRelogio então porque criar EnumSexo ou IBanco ?
Banco é Banco. Se precisa de formas diferentes crie outros nomes prefixo comuns são Default, Abstract, Generic
O principio de encapsulamento implica que interface e classe devem ser indistinguíveis. Vcs violam isso usando prefixos como I e Enum. Não ha necessidade.

Uma outra coisa que faz pouco, ou nenhum sentido, é a herança de um objeto com um monte de métodos estáticos para verificar nulidade. Isso caberia numa classe utilitária e dificilmente num objeto padrão, muito menos num “Layer SuperType” de onde todo o mundo herda. Isso é bem estanho. [/quote]

Nem todos no projeto são a favor desses prefixos, alguns concordam inteiramente com a sua colocação.

Foi apresentado o argumento que um tipo, por exemplo sendo uma interface, não possui o mesmo comportamento se o mesmo for uma classe, mas eles não deram muita importância. Perguntou-se, por que as IDEs diferenciam esses tipos com ícones diferentes? Posso dar um new em uma interface?

Se eu souber antecipadamente que aquele identificador é uma interface nem tento fazer isso. Esse tipo de coisa e discussão tinha sempre. Então encaramos isso mais como um estilo de codificação do que princípios O.O. Ou seja, no momento encaramos como semântica para tipagem O.O. Temos a mania(padrão de codifição) para colocar prefixos como View4PDF, (lêr-se viu For pdf) e por aí vai. Muito já foi discutido no grupo JRimum, aqui vou colocar algumas coisas da lista de desenvolvedores do jrimum:

Outra coisa, em validações de tecnologias de persistência passamos pelo problema de que elas (Hibernate, JPA, etc) não aceitavam interfaces no mapeamento. E o principio: programe para uma interface não para uma implementação.? Então, paramos de nos preocupar muito com esse padrão de nomes e continuamos com os requisitos funcionais.

Mas estamos abertos para sugestões e padronizações nacionais também, o GUJ poderia fazer, sei lá, uma enquete para uma dada padronização nacional.

Não sei, mas fica aqui o registro que queremos aumentar o reuso e a usabilidade para nós brasileiros.

Gostamos de legibilidade e tentamos ser práticos, achamos melhor fazer:

 if(isNotNull(codigoDeBarras))
   //do; 

do que

if(codigoDeBarras != null)
  //do;

O Intellisense é muito melhor para esse tipo de coisa.

Ou ainda:

 if(exists(aPessoa) 

do que:

if(aPessoa != null)

Ou ainda:

if(isNotNull(valor,"O paramentro valor não pode ser nulo!")

No lugar de:

if(valor != null)
//do;
else
throw new IllegalArgumentException("O paramentro valor não pode ser nulo!");

Melhor que isso seja uma coisa básica de todas as classes se não teremos que ficar importando isso toda hora. Além do que o método toString() de Object utiliza o ToStringBuilder do commons do apache, isso também fica em um lugar só, assim não preciso fazer um para cada classe.

Além do logging também, como não usamos AOP, isso tudo fica em um lugar só fica como serviços básicos da classe, para o nosso propósito e no nosso pensamento lógico.

Esses foram os aspectos que consideramos para esse Object do JRimum.Embora consideremos mais como uma decisão de praticidade mesmo. Mas pode ser que seja uma atrocidade ou barbaridade para algum principio de programação. Desconheço como uma ofensa grave, reconheço que não é nenhum tipo de “Boa Prática”.

Tri massa o projeto, legal ver a iniciativa do pessoal, mas na minha sincera opinião, não vejo motivos pra sair criando projetos que ja fazem o que outros muitos fazem só porquê uma ou outra feature não me agrada ou não existe, seria legal o pessoal colaborar com os projetos já existentes e acabar um pouco com essa confusão, mas enfim, parabéns.

Agora, me corrijam se eu estiver errado, o ‘número’ do RG não é composto somente por números, até onde eu me lembro em Santa Catarina, por exemplo, eles têm letras também, não sei se isto acontece em outros estados, sendo assim setNumero na classe RG deveria receber alguma outra coisa mas não um long.

Mesmo porque o correto é FEMININO.

Mas, brincadeiras à parte.

Acho sempre louvável as iniciativas de se desenvolver projetos que busquem resolver problemas recorrentes, ainda mais para comunidades específicas, como é o caso da comunidade brasileira, que carece de soluções mais focadas ao nosso cotidiano.

Acho legal vocês buscarem uma aderência ao DDD, mas acredito ser esmero ou utopia demais modelar as classes desta forma, haja vista que pouquíssimos irão de fato usufruir destas facilidades.

EU, por exemplo, dificilmente usaria pessoa.addRG(rg). Certamente eu usaria Pessoa do meu modelo, podendo até incorporar o RG do projeto.

Sou mais a favor do KISS, neste caso, pois trata-se de biblioteca utilitária (genérica) e não específica ao problema de negócio. Assim acaba podendo engessar o desenvolvimento.

[quote=mrblack]…

Agora, me corrijam se eu estiver errado, o ‘número’ do RG não é composto somente por números, até onde eu me lembro em Santa Catarina, por exemplo, eles têm letras também, não sei se isto acontece em outros estados, sendo assim setNumero na classe RG deveria receber alguma outra coisa mas não um long.[/quote]

Realmente, ja vi uma pessoa que tinha RG emitido pelo exército que tinha números + letras.

[quote=Paulo Silveira][quote=sergiotaborda]
Me referia ao fato de pessoa ter uma coleção de RG, e não apenas um, e não à nomenclatura do método.
[/quote]

Ops, desculpa, tem razao. Mas eu queria saber a sua opiniao sobre a nomenclatura mesmo. Se por exemplo o metodo addEndereco na classe Pessoa é incorreto (deveria ser addAddress ou adicionaEndereco) ou se tambem entra no seu elogio "finalmente uma coisa feita com pés-e-cabeça. ". Na minha opiniao nao ha problema algum, queria saber se a sua mudou, dada a ausencia de criticas nesse quesito, onde voce costuma bater forte.[/quote]

Chega a um ponto onde não vale a pena bater mais na mesma tecla. A minha opinião não mudou, mas não haveria nenhum proveito em repetir os argumentos da outra thread. Ainda me acusariam de alguma coisa ruim… sei lá… Se esta API tivesse escolhido um caminho diferente ai sim seria interessante reavivar a discussão, mas como não, enquanto não tiver melhores argumentos não vou ocupar espaço com isso.

Eu conheço as vantagems da normalização e espero que os outros conhecam também. O argumento dado no outro thread que é uma decisão de desing e que tem a regra X e Y é válido. É uma normalização. Não é normalização ao nivel de uma ISO ou W3C etc… mas é válido. O problema é a justificativa da escolha da normalização, que eu acho que normalmente não é completamente honesta. Sobretudo numa API publica gratuita. Mas não posso afirmar que a falta de honestidade é proposital ou apenas por desconhecimento ou falta de “self-understanding” da organização por detrás da API.

O elogio de “com pés-e-cabeça” advem do design mais cuidado que a API brasileria média que vejo por ai. Alguem disse que fazia o mesmo que o JBoleto. Pode ser, mas as API não têm o mesmo design , ou seja, não têm a mesma qualidade. Para quem faz API publicas isso deveria ser uma preocupação. Por exemplo a API do JasperReports é excelentemente construida. É muito flexivel. A do JFreechart é muito ruim. Não ha uma classe única que vc usa, vc tem que usar uma classe especial de dados para cada gráfico. Isso é imperfeito porque 90% dos gráficos são comutáveis. ( grafico de pizza ou de barras é a mesma coisa representada diferente) Tudo bem que para gráficos especiais hajam classes especiais, mas sem abusar. Foi só um exemplo para ilustrar o que quero dizer.

[quote=gilmatryx][quote=sergiotaborda]
Uma outra coisa que faz pouco, ou nenhum sentido, é a herança de um objeto com um monte de métodos estáticos para verificar nulidade. Isso caberia numa classe utilitária e dificilmente num objeto padrão, muito menos num “Layer SuperType” de onde todo o mundo herda. Isso é bem estanho.
[/quote]

Gostamos de legibilidade e tentamos ser práticos, achamos melhor fazer:
(…)
O Intellisense é muito melhor para esse tipo de coisa.

Melhor que isso seja uma coisa básica de todas as classes se não teremos que ficar importando isso toda hora.
[/quote]

O seu argumento é, basciamente, “temos perguiça de fazer import de um classe utilitária e por isso optamos por enchar todas as classes com todos os métodos utilitátios possiveis”. É um péssimo argumento.
Voce resolve tudo isso de forma elegante criando uma classe utilitária de métodos estáticos ( à lá Math) e usando static import.
Como isso vc escreve exactamente os codigos que mostrou mas sem pesar nas classes que interessam.

Veja o exemplo do JUnit. Ele define os métodos assertXXX dessa forma. Nas versões antigas era métodos da classe de teste, mas isso era porque existia uma classe de teste. Agora que isso não existe mais, os métodos são chamados via import estático

Isso é uma falha no encapsulamento (API leakeage). Quem usa a sua API não tem culpa das API que vc usa. Não precisa nem saber. Não ha problema nenhum em especificar toString() em uma interface ( vide CharSequence) mas tem que ser por um bom motivo. Se não , Object já define isso.

Por outro lado usar uma API externa para escrever o toString é forçar a barra. Vc não precisa disso. Meio que passa a ideia de que vc não sabe escrever o toString…

Pois é, esse é o problema de sempre: “o nosso pensamento logico” e o pensamento logico dos usuários da sua API? não interessam ? e as boas práticas ?

[quote]
Esses foram os aspectos que consideramos para esse Object do JRimum.Embora consideremos mais como uma decisão de praticidade mesmo. Mas pode ser que seja uma atrocidade ou barbaridade para algum principio de programação. Desconheço como uma ofensa grave, reconheço que não é nenhum tipo de “Boa Prática”.[/quote]

Ainda bem que reconhece. ainda está a tempo de mudar isso na versão 2

[quote=gilmatryx][quote=sergiotaborda]
Vc não cria classes chamadas ClassCliente nem InterfaceRelogio então porque criar EnumSexo ou IBanco ?
Banco é Banco. Se precisa de formas diferentes crie outros nomes prefixo comuns são Default, Abstract, Generic
O principio de encapsulamento implica que interface e classe devem ser indistinguíveis. Vcs violam isso usando prefixos como I e Enum. Não ha necessidade.
[/quote]

Nem todos no projeto são a favor desses prefixos, alguns concordam inteiramente com a sua colocação.

Foi apresentado o argumento que um tipo, por exemplo sendo uma interface, não possui o mesmo comportamento se o mesmo for uma classe, mas eles não deram muita importância. Perguntou-se, por que as IDEs diferenciam esses tipos com ícones diferentes? Posso dar um new em uma interface? Se eu souber antecipadamente que aquele identificador é uma interface nem tento fazer isso.
[/quote]

Vc está brincado , certo ? Desde quando o que um IDE faz é argumento ?
O IDE põe icones diferentes porque ele pode. apenas isso. Um IDE é um aplicativo gráfico ele precisa passar informações gráficamente. Esse, com certeza, não é o foco de uma API.

O ponto é exactamente ao contrário. Interfaces e classes não devem ser destinguiveis. Se alguem tentar dar new numa interface não tem problema ( classe anonima são feita assim). Interfaces são importantes. Defender o programador da sua ignorania não é uma preocupação de quem constroi uma API publica. Se o cara tenta dar new num enum o problema é dele, não dos designers da API.

Quanto aos nomes: Nomenclatura é primeiro pilar de qualquer norma. Até da linguagem omnipresente. Não é algo que se possa desconsiderar ou levar “na boa”. Isso é pricipalmente assim quando a API é publica. Se fosse privada o problema seria da organização, mas sendo publica o problema é de todo o mundo. O sucesso da sua API depende de quão inteligivel ela é e não apenas do que ela faz.

Dois problemas ai

  1. Discutir muito não signfiica nada. Os politicos fazem a vida discutindo.
  2. A API é publica, logo o que a equipe de desenvolvimento pensa ou acha equivale a 40% da solução. A opinião de quem vai usar precisa ser ouvida.

Este assunto não tem nada a haver com ser brasileiro , de brasileiro ou para brasileiro. Nem tem nada a haver com a funcionaldiade da API. Tem a haver com o design da API. O seguimento de normas, padrões , coisas com que o mundo concorda e não apenas meia duzia de pessoas.

Pareceu-me haver uma preocupação com o seguimento de padrões relativos ao dominio ( os padrões das associações de bancos) e isso é bom. Seguir padrões como small data types, etc… Tudo isso é bom. Mas se não for acompanhado de uma normal de design vai tudo para o lixo. E por “norma” me refiro a algo imparcial, aceite e usado pela maioria

Por exemplo, não fazia muito sentido ter smal data types mutáveis. Eu desconfiei- e já confirou- que é por causa do hibernate ,etc…
Isso é uma falha no design. É API leakage. É preocupar-se demais com o como a para o quê a API irá ser usada. É bom fornecer ganchos mas não é bom supor demais ( early otimization) Por exemplo, bastaria os small data types serem extenciveis para que, quem precisar, os estenda e torne compativel com o hibernate. Ou a propria API pode ter um pacote de compatibilidade desse tipo.
Mas não precisa fazer parte do core da API.

Claro, podemos sim, qual é sua proposta de como trabalhar?
Seremos fornecedores um do outro, tipo fazemos o domínio e vcs os validadores?
Ou modelamos em conjunto para um dos projetos?
OU juntamos os projetos?
Não tenho nem idéia. Como seria? Eu particularmente estou disposto sim. Agregando valor , …
Tamos aí.

Quanto a sair criando projetos indiscriminadamente…, bom não sou a favor, falei anteriormente que ia ter que mudar todo um projeto existente e muitas vezes os envolvidos (donos dos projetos) relutam, não concordam ,não aceitam, etc.

Referente ao RG não tínhamos como validar na hora do design essa informação, mas foi discutido. Como não é vital para o boleto bancário (que focamos no momento) acabou que esquecemos. Obrigado pela observação.

Bom, já falei que focamos no componente bancário (boleto) e pra ser sincero com todos, mais especificamente no domínio bancário. É normal que sistemas corporativos se utilizem de meios para fazer integrações com bancos (instituição financeira) e o modelo que estávamos pensando no momento de design era esse.

Mas caso a comunidade opine, em maioria, por mais flexibilidade e independência, …, acho que tomaremos outro rumo no design.

Cara, vc realmente está por dentro do desenvolvimento do projeto, capturou rapidinho os bons e maus costumes nossos. Olha o que tenho a te dizer é que ser preguiçoso hoje em dia é moda :D.

Na verdade queremos realmente esse tipo de observação. Pelo que vc está falando, vc não gostaria de ter esses métodos comparativos em qualquer classe que vc use. Pelo que entendi, se a Sun colocasse esse tipo de método hoje em Object vc não iria gostar, pois vc provavelmente não usa muito.
A questão para nós foi, Bicho, toda hora ter que saber da nulidade ou não de uma referência é normal para nós, vamos fazer assim. Todos quando estavam usando gostaram, lógico é uma pequena amostra de desenvolvedores, mas mostrou-se útil. Uso esse tipo de comparação toda hora em outros projetos acho super útil. Acho que a palavra super pesou muito. :slight_smile:

Lembro de novo o projeto ta incubado para isso. Se nós não tivéssemos deixado esses métodos teríamos ter que explicar e um protótipo é sempre melhor. Mas UMA VEZ muito obrigado.
Mas até agora só vc falou desse ponto. Queríamos que o pessoal falasse também gostando ou não.

Cara a interface é para dizer que todos os nossos objetos devem ser serializáveis e que o toString() deve ser usado para exibir os atributos e valores do objeto. Para nós ele só serve para isso, aí no momento de uma exceção os valores são escritos. Caso o usuário não queira esse comportamento…, sobrescreve o método.
Já em escrever o meu próprio toString(), onde fica o reuso se eu tenho uma classe que faz isso para mim perfeitamente. Não concordo não, nem acho que seja forçar a barra, isso sim é uma coisa a lá Math ou Util. Caso o usuário da API queria um logging mais apurado habilitando o nível mais detalhado, ele vai ver uma coisa como essa:

2008-06-19 23:04:11,046 DEBUG main jrimum.ACurbitaObject.<init> (Boleto.java:145)-titulo instance : JRimumObject: 
(...)
br.com.nordestefomento.jrimum.domkee.type.EnumUnidadeFederativa@1cde100[nome=Distrito Federal,sigla=DF,capital=Brasília,name=DF,ordinal=26],pais=<null>,pessoas=<null>]],contasBancarias=<null>],aceite=A]
 2008-06-19 23:04:11,296 DEBUG main jrimum.ACurbitaObject.create (ACampoLivre.java:82)-titulo instance : JRimumObject: 

Já pensou em escrever um toString que informasse os valores assim para cada classe? Não me agrada nem um pouco a idéia. Só escrevemos para as que tem tipos pesados nos atributos, como um File da vida.

Adicionado posteriormente caso alguém leia a thread. Exemplo de uso do commons para toString equals e hashCode:

https://jaxb2-commons.dev.java.net/commons-lang-plugin/

Pois é, estamos aqui para ouvi e melhorar, e vc tem ajudando bastante, estamos bastante gratos com suas observações.

Entendo que uma IDE como o Eclipse, NetBeans,etc, são o resultado de muito uso, pesquisa e representam toda uma cultura relacionada a programação. Um ícone ( Coisa, fato, pessoa, etc., que evoca fortemente certas qualidades ou características de algo, ou que é muito representativo dele ) usado para uma interface e um diferente para classe tem uma razão não acha?
Por que será que o padrão javadoc dá escreve interfaces em itálico, classes abstratas tem no identificador da classe a palavra abstract? Por que jamais iremos escrever uma interface e uma classe com o mesmo nome a não ser que estejam em pacotes diferentes?
Acho que é porque são diferentes. :slight_smile:

Me dá uma sugestão para escrever um Enumeration, uma classe concreta, uma classe abstrata e uma interface para um Título. Sério, não to tirando onda não. Nós temos esse caso. Tudo referente a título.

Concordo plenamente, mas, até agora, só vc opinou sobre isso. Gostaria que o pessoal falasse mais a respeito afinal não é só de um grupo, é público.

Por isso estamos aqui ouvindo a todos e anotando tudo para tentar melhorar. Muito já foi discutido no JRimum sobre isso e tomamos uma decisão e pronto. Se ficássemos ouvindo colocando em fórum, ouvindo, etc… A API não estaria em uma versão de avaliação. Desta forma viemos para cá com uma exemplo (A versão incubada) onde fica fácil a comunicação a respeito das soluções e decisões tomadas.

Quis dizer que estamos aqui para ouvir as sugestões dos quase 188.000.000 de brasileiros caso todos seja programadores. Estamos aqui para ouvir, entender e contribuir estamos com vc e com todos os outros. É uma questão de ser brasileiro sim, por que se nós (A maioria dos brasileiros) decidisse que a codificação da API deveria ser com acentuação nós assim faríamos, o problema é que poucas pessoas ajudam como vc. Seguir o padrão mundial é o ideal mas nem sempre o Real. E também se alguém aparecesse com uma solução que fugisse do padrão mundial mas que melhorasse o nosso lado faríamos na mesma hora. As vezes é preciso criar padrões. Não que seja o nosso caso.

Olha só, até agora a maioria aqui é vc. Mais uma vez obrigado pelo feedback. Sim e tiny types não era padrão algum até pouco tempo, tipo, um ano.

Da pra dar um exemplo essa não ficou muito claro, por que não faz muito sentido ser mutável?

Fala galera…

Pessoal, gostaria primeiramente de agradecer o feedback aí de vocês, Isso é muito importante para que a biblioteca Bobepo e o Projeto JRimum como um todo possa evoluir.

Estou observando cada post, assim como meus companheiros de projeto, e tenham certeza que tudo o que vocês falaram por aqui vai ser abordado nos encontros do grupo JRimum.

Gilmar e Rômulo já responderam a vários questionamentos, então não vou ser redundante, mas quero fazer apenas um pequeno comentário sobre:

[quote=boaglio]
Pelo que vi ele tem um projeto chamado Bopepo que faz a mesma coisa que o JBoleto faz… [/quote]
Não! Não faz a mesma coisa! O fato de gerar boletos bancários é uma característica que as bibliotecas Bopepo e JBoleto têem em comum, entretanto o Bopepo é bem diferente em vários aspectos, como por exemplo no design das classes (visando reuso), documentação, e principalmente no tocante aos recursos de “personalização livre do boleto” e “flexibilidade”.

Isto que estou falando pode ser visto de maneira bem clara nos novos tutoriais que acabei de disponibilizar no site do grupo JRimum:
Gerando boletos bancários: Boleto em 3 minutos!
Gerando boletos personalizados: Boleto personalizado com imagens, textos estáticos e dinâmicos definidos “a mão livre” pelo usuário.

Dêem uma olhada nos vídeos, sobretudo no Gerando boletos personalizados que vocês vão começar a descobrir algumas das diferenças ente Bopepo e JBoleto.

Um abraço a todos.
Grato pelo feedback. :-o