【问题标题】:How to persist classes like java.util.Currency?如何持久化 java.util.Currency 之类的类?
【发布时间】:2015-04-14 05:44:21
【问题描述】:

我正在使用休眠来保存我的数据。这是一个金融应用程序,我很难坚持应用程序中最基本的实体,即“金钱”。我正在使用 JodaMoney,但它是不可变的,所以我无法找到一个好的方法来坚持它。如果不将我的钱存入数据库,那么制作应用程序就没有意义。当我什至无法存储对象的状态时,我会如何处理不变性? 然后我开始创建自己的“货币”(字段为 BigDecimal 金额,java.util.Currency 为货币),我想使用 java.util 的“货币”。但是,它没有公共构造函数,所以休眠不能持久。 请指导我如何处理这个问题?

EDIT1:最基本的类的代码:

@Entity
public class BasicMoney {

    @Embedded
    @Id
    private BigDecimal amount;
    @Embedded
    private Currency currency;
    //getters and setters, other methods
}

现在,当我创建此类的对象并尝试将其存储到数据库中时,它不起作用。休眠抛出:

org.hibernate.InstantiationException:没有实体的默认构造函数::java.util.Currency

所以,这就是我面临的问题。

【问题讨论】:

  • 理论很多,没有代码....这不是提问的好方法!!!
  • 发布你的尝试
  • @AnkitLamba 我已经添加了代码,虽然它是一个非常基本的代码,但我的主要问题是如何处理这种情况?

标签: java hibernate persistence


【解决方案1】:

与其处理货币字符串和金额,不如让 Hibernate 了解您的类型。这样你就可以:

private Money amount;

而不是

private BigDecimal amount;
private String currency;

所以你不需要到处转换。

我是这样做的:

1) 使用 JavaMoney 代替 JodaMoney,该 JSR-354 项目预计将包含在 Java 9 中。如果您想坚持使用 JodaMoney,则不需要下面的第 3 步。

2) 将此 UserType library 添加到您的类路径

3) 创建这个简单的类:

   public class CustomPersistentMoneyAmountAndCurrency extends AbstractMultiColumnUserType<MonetaryAmount> {  

    private static final ColumnMapper<?, ?>[] COLUMN_MAPPERS = new ColumnMapper<?, ?>[] { new CustomStringColumnCurrencyUnitMapper(), new BigDecimalBigDecimalColumnMapper() };

    private static final String[] PROPERTY_NAMES = new String[]{ "currency", "number" };

    @Override
    protected ColumnMapper<?, ?>[] getColumnMappers() {
        return COLUMN_MAPPERS;
    }

    @Override
    protected Money fromConvertedColumns(Object[] convertedColumns) {

        CurrencyUnit currencyUnitPart = (CurrencyUnit) convertedColumns[0];
        BigDecimal amountPart = (BigDecimal) convertedColumns[1];
        return Money.of(amountPart, currencyUnitPart);
    }

    @Override
    protected Object[] toConvertedColumns(MonetaryAmount value) {

        return new Object[] { value.getCurrency(), value.getNumber().numberValue(BigDecimal.class) };
    }

    @Override
    public String[] getPropertyNames() {
        return PROPERTY_NAMES;
    }
}

4) 现在,无论您想在您的实体中使用什么,您都可以这样做:

   @TypeDefs(value = {
        @TypeDef(name = "moneyAmountWithCurrencyType", typeClass =        CustomPersistentMoneyAmountAndCurrency.class)
})
@Entity
@Table(name = "account_entry")
public class AccountEntry {

    private Money referenceMoney;
    ...
    @Basic( optional = false )
    @Columns(columns = {
            @Column( name = "reference_money_currency", nullable = false, length = 3  ),
            @Column( name = "reference_money", nullable = false  )
    })
    @Type(type = "moneyAmountWithCurrencyType")
    public Money getReferenceMoney() {
        return this.referenceMoney;
    }
  }

就是这样。您将在整个过程中获得强大的打字。

【讨论】:

    【解决方案2】:

    【讨论】:

      【解决方案3】:

      您可以使用解决方法

      @Embedded
      String currency; //store data as a string
      
      public void setCurrency(Currency currency) {
          this.currency = currency.getCurrencyCode(); //conversion to an actual currency
      }
      
      public Currency getCurrency() {
          return Currency.getInstance(currency); //conversion to an actual currency
      }
      

      【讨论】:

      • 非常感谢!!!这很有意义。我对此只有一个担心,每次我调用 getCurrency() 方法时,它都必须创建新的货币对象,那不是很贵吗?我可以考虑的一个解决方法是制作另一个“@Transient”字段,该字段永久存储 Currency 对象,因此 getter 不必在每次调用时都构造它。您对此有何看法?
      • 试试 System.out.println(Currency.getInstance("USD") == Currency.getInstance("USD"));它返回真
      • 好吧,是的,它返回 true,这意味着 Currency 类返回相同的实例。我刚刚也检查了 java.util.Currency 中的方法,我明白了,它使用字符串键维护货币对象的 Map。因此,它不会每次都构造新对象。再次感谢 Evgeniy ! :)
      • 我得到一个编译器错误@Embedded 属性类型不应该是“字符串”
      【解决方案4】:

      抱歉,回答晚了,但我没有将此选项视为答案,我认为它非常优雅。您可以将 JPA 转换器与自动应用一起使用:

      @Converter(autoApply = true)
      public class CurrencyConverter implements AttributeConverter<Currency, String> {
      
          @Override
          public String convertToDatabaseColumn(Currency currency) {
              return currency.getCurrencyCode();
          }
      
          @Override
          public Currency convertToEntityAttribute(String currencyCode) {
              return Currency.getInstance(currencyCode);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-20
        • 1970-01-01
        • 2013-01-25
        • 2014-11-27
        • 1970-01-01
        相关资源
        最近更新 更多