This section covers some advanced JPA 2.1 mapping features.
JPA 2.1 defines converters for translating data values from Java to database specific values. Converters make it easy to write Java interpreters for special monetary values, enumerated text values, and Boolean values. It is very common in business to have different designations for Boolean in a production database. Some tables may have text columns, say T, F or Y, N and others have integers 0 and 1.
Here is a converter that translates trade data in a database in order to determine if the bank is buying or selling to and from a counterparty.
enum Direction { BUY, SELL } @Converter public class TradeDirectionConverter implements AttributeConverter<Direction,String> { @Override public String convertToDatabaseColumn(Direction attribute) { switch (attribute) { case BUY: return ""P""; default: return ""S""; } } @Override public Direction convertToEntityAttribute(String dbData) { dbData = dbData.trim().toLowerCase(); if ( dbData.equals(""P"")) return Direction.BUY; else return Direction.SELL; } }
The convertor class
TradeDirectionConverter
extends the AttributeConverter
Java generic interface, new in JPA 2.1. The developer simply implements two methods convertToEntityAttribute()
and convertToDatabaseColumn()
as the conversion process is bidirectional.
We can apply this converter to the entities with the Direction
type. Here is an example of the converter in a foreign-exchange bank trade entity.
@Entity @Table(name = ""FXTRADE"") public class ForexTrade { /* ... */ @Convert(converter=TradeDirectionConverter.class) Direction direction; /* ... */ }
We explicitly declare the convertor with the
@Convert
annotation that references the conversion class.
JPA 2.1 also allows converters to be applied globally across the entire domain. To allow this, the converter must be annotated as @Converter(autoApply = true)
. Global convertors do not require an entity to be explicitly annotated with @Convert
on the field or properties. These definitions, therefore, can be removed for global converters.
It is possible to build a projection, which is a partial view of an entity having a narrower collection of columns, with a JPQL statement using the syntax: SELECT NEW
. Unfortunately, in the previous specification, it was not possible to write native SQL using JPA to build entities and non-entities.
Here is a JPQL query to view a financial banking trade as a non-entity:
SELECT NEW TradeView(t.id, t.book, t.tradeDate, t.settlementDate, t.amount, t.ccy ) FROM Counterparty c JOIN c.trades t WHERE t.amount >= 250000 AND t.book = ""Exchange West"" AND t.ccy = ""USD""
In JPA 2.1 the new annotation @ConstructorResult
is designed for native SQL queries to build an entity or non-entity. The @ConstructorResult
is combined with the
@ColumnResult
to build a dynamic constructor argument list by type.
Here is an example of a native SQL query that creates a bond trade:
@NamedNativeQuery( name=""BondTradeView.findByAccountId"", query=""SELECT B.TRADE_ID, B.NOTIONAL, A.ACC_NAME, ""+""A.CPTY_NAME FROM TRADE B, ACCOUNT A ""+""WHERE B.TYPE=''BOND'' ""+""AND B.ACC_ID = A.ACC_ID AND A.ACC = :ID "",resultSetMapping=""bondtradeview"" ) @SqlResultSetMapping(name=""bondtradeview"", classes={ @ConstructorResult(targetClass=BondTradeView.class, columns={ @ColumnResult(name=""TRADE_ID"", type=Integer.class), @ColumnResult(name=""NOTIONAL"", type=BigDecimal.class), @ColumnResult(name=""ACC_NAME"", type=String.class), @ColumnResult(name=""CPTY_NAME"", type=String.class) }) } ) public class BondTradeView { /* ... */ }
In order to use @ConstructorResult
correctly, we must apply it to a SQL result set mapping and also the named native query.
3.145.12.156