Tipo Moeda e JPA

Oi pessoal,
desenvolvi uma classe para representar os valores de moeda ( Currency extends BigDecimal ). Em outra classe chamada nota mapiei algo como (tirei vários atributos que não interessam para o problema que eu desejo discutir):

@Entity
@Table(name = “nota”)
@NamedQuery(name=Constants.NOTA_ULTIMA_NOTA, query=“select max(n.numero) from Nota n”)
public class Nota implements Serializable, Comparable{
@Id
@Column(name = “numero”, precision = 6, scale = 0)
private int numero;
@Column(name = “total”, precision = 9, scale = 2)
private Currency total;
(…)

O problema é que quando tento persistir um objeto nota (banco HSQLDB / campo total está definido como Numeric), surge o erro abaixo:

Hibernate: select nota0_.numero as numero11_0_, nota0_.cod_cliente as cod8_11_0_, nota0_.emissao as emissao11_0_, nota0_.cod_empresa as cod9_11_0_, nota0_.numeroCupom as numeroCu3_11_0_, nota0_.numeroEcf as numeroEcf11_0_, nota0_.obs as obs11_0_, nota0_.saidaEntrada as saidaEnt6_11_0_, nota0_.total as total11_0_ from nota nota0_ where nota0_.numero=?
Hibernate: insert into nota (cod_cliente, emissao, cod_empresa, numeroCupom, numeroEcf, obs, saidaEntrada, total, numero) values (?, ?, ?, ?, ?, ?, ?, ?, ?)
Erro ao persistir nota
javax.persistence.PersistenceException: org.hibernate.exception.SQLGrammarException: could not insert: [br.com.autocominformatica.ecfserver.model.notas.Nota]
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:630)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:300)
at br.com.autocominformatica.ecfserver.util.JPAHelper.commit(JPAHelper.java:133)
at br.com.autocominformatica.ecfserver.action.ferramentas.NotaActionTest.montaNota(NotaActionTest.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.internal.runners.TestMethodRunner.executeMethodBody(TestMethodRunner.java:99)
at org.junit.internal.runners.TestMethodRunner.runUnprotected(TestMethodRunner.java:81)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestMethodRunner.runMethod(TestMethodRunner.java:75)
at org.junit.internal.runners.TestMethodRunner.run(TestMethodRunner.java:45)
at org.junit.internal.runners.TestClassMethodsRunner.invokeTestMethod(TestClassMethodsRunner.java:71)
at org.junit.internal.runners.TestClassMethodsRunner.run(TestClassMethodsRunner.java:35)
at org.junit.internal.runners.TestClassRunner$1.runUnprotected(TestClassRunner.java:42)
at org.junit.internal.runners.BeforeAndAfterRunner.runProtected(BeforeAndAfterRunner.java:34)
at org.junit.internal.runners.TestClassRunner.run(TestClassRunner.java:52)
at junit.framework.JUnit4TestAdapter.run(JUnit4TestAdapter.java:32)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.run(JUnitTestRunner.java:421)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.launch(JUnitTestRunner.java:912)
at org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner.main(JUnitTestRunner.java:766)
Caused by: org.hibernate.exception.SQLGrammarException: could not insert: [br.com.autocominformatica.ecfserver.model.notas.Nota]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:67)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2272)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2665)
at org.hibernate.action.EntityInsertAction.execute(EntityInsertAction.java:60)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:167)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:297)
… 20 more
Caused by: java.sql.SQLException: Wrong data type: java.lang.NumberFormatException
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.setParameter(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.setBytes(Unknown Source)
at org.hibernate.type.AbstractBynaryType.set(AbstractBynaryType.java:43)

Já fiz alguns testes e se mudo o atributo total da classe Nota para BigDecimal, tudo funciona perfeitamente. Alguém sabe o que estou fazendo de errado? Acredito que deveria mapear de uma maneira diferente o tipo Currency no JPA, mas não sei como.
Agradeço qualquer comentário.

Porque você criou este Currency? O que ele tem a mais que BigDecimal?
Apesar de Currency ser um BgiDecimal, o JPA pode não estar reconhecendo isso e dando problemas ai.

Oi Daniel,
esta classe apenas facilita um pouco o trabalho em algumas operações lógicas, tipo divisão com arredondamento para duas casas decimais, conversões entre BigDecimal e Double, alguns construtores específicos para as minhas classes de negócio… Na verdade nada que seja tão importante mas, o fato é que eu gostaria de saber como mapear um caso destes no JPA. Acho que pode surgir algum caso similar no futuro então não quero simplesmente mudar tudo de Currency para BigDecimal e esquecer o problema.

Mauricio

O atributo columnDefinition de @Column não resolve?

Toplink tem umas coisas a mais: http://www.oracle.com/technology/products/ias/toplink/doc/11110/devguide/jpatlext.htm#BABDBBJC

Veja se tem isso pra Hibernate.

O columnDefinition não teve efeito. Pelo que eu entendi é só pra você determinar o tipo SQL que será gerado. Tentei com NUMERIC(9,2) mas, o erro continua o mesmo.
O Hibernate tem uma extensão para definir “user types” (@org.hibernate.annotations.TypeDef) semelhante a esta do TopLink. Mas, eu estava tentando ficar dentro do padrão JPA para não perder portabilidade. Estou chegando a conclusão que não tem jeito a não ser partir pra isso mesmo.
Ainda assim, valeu mesmo a dica.

Portabilidade?
Bom, sua aplicação vai mudar de BD facilmente ou é daquelas aplicações que ficam no cliente X que usa banco de dados Y com um histórico de dados que daria pra ir daqui até a Lua?

Fala mau.mss, tudo bem ?

Cara estou com o mesmo problema seu. Tenho uma classe Moeda que extends BigDecimal, e em uma outra classe Venda tenho o atributo Valor que é uma Moeda. Com isso quando mando persistir apresenta o mesmo problema.

Você conseguiu achar alguma solução com relação a isso ?

Aguardo e obrigado por enquanto !