I just converted all of my java.math.BigDecimal
usages to javax.money.MonetaryAmount
(where they represented money). I am currently "assuming" the currency to be USD with the help of a MoneyUtils
to avoid adding extra database columns that will only contain "USD" in them. This can be seen in the next 2 snippets.
@Converter(autoApply = true)
public class MonetaryAmountConverter
implements AttributeConverter<MonetaryAmount, BigDecimal> {
@Override
public BigDecimal convertToDatabaseColumn(final MonetaryAmount monetaryAmount) {
return DefaultUtils.defaultOrNull(
monetaryAmount,
ma -> ma.getNumber().numberValue(BigDecimal.class));
}
@Override
public MonetaryAmount convertToEntityAttribute(final BigDecimal monetaryAmountValue) {
if (monetaryAmountValue == null) {
return null;
} else {
return MoneyUtils.of(monetaryAmountValue);
}
}
}
public final class MoneyUtils {
public static final CurrencyUnit DOLLAR = Monetary.getCurrency(Locale.US);
public static MonetaryAmount of(@NonNull final BigDecimal value) {
return Money.of(value, MoneyUtils.DOLLAR);
}
}
I have this @Repository
method that should give me a sum, which could be null
if no rows match:
@Query("query that can return null or a numeric")
MonetaryAmount sumSomeData();
The problem is that it doesn't go through my MonetaryAmountConverter
. I tried adding a @Convert
directly to the method but it didn't work.
@Query("query that can return null or a numeric")
@Convert(converter = MonetaryAmountConverter.class)
MonetaryAmount sumSomeData();
So it appears that an AttributeConverter
with @Converter(autoApply = true)
applies to JPA Entity fields, but not to method return types, even when @Convert
is added to the method signature.
You can use a constructor expression:
The SELECT clause identifies which objects and values to return as the query results. The expressions discussed in Section 11.4, “Expressions” are all valid select expressions, except where otherwise noted. See the section Section 11.10, “Query API” for information on handling the results depending on the types of values specified in the SELECT clause.
There is a particular expression type that is only valid in the select clause. Hibernate calls this “dynamic instantiation”. JPQL supports some of that feature and calls it a “constructor expression”
General example:
select new Person(user.name, address)
from User as user
left join user.address as address
Before you ask, no, you cannot call methods, only constructors. Also, you'll need to consider the fact that your query may return null
. You could write a wrapper class.
public final class MonetaryAmountWrapper {
public MonetaryAmountWrapper(final BigDecimal value) {
this.monetaryAmount = Money.of(value, MoneyUtils.DOLLAR);
}
private final MonetaryAmount monetaryAmount;
}