JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-007UserTypes的用法(@org.hibernate.annotations.Type、@org.hibernate.annotations.TypeDefs、CompositeUserType、DynamicParameterizedType、、、)
一、结构

二、Hibernate支持的UserTypes接口
UserType —You can transform values by interacting with the plain JDBC PreparedStatement (when storing data) and ResultSet (when loading data).By implementing this interface, you can also control how Hibernate caches and
dirty-checks values. The adapter for MonetaryAmount has to implement this interface.
CompositeUserType —This extends UserType , providing Hibernate with more details about your adapted class. You can tell Hibernate that the MonetaryAmount component has two properties: amount and currency . You can then reference these properties in queries with dot notation: for example, select avg(i.buyNowPrice.amount) from Item i .
ParameterizedUserType —This provides settings to your adapter in mappings.You have to implement this interface for the MonetaryAmount conversion,because in some mappings you want to convert the amount to US dollars and in
other mappings to Euros. You only have to write a single adapter and can customize its behavior when mapping a property.
DynamicParameterizedType —This more powerful settings API gives you access to dynamic information in the adapter, such as the mapped column and table names. You might as well use this instead of ParameterizedUserType ; there is no additional cost or complexity.
EnhancedUserType —This is an optional interface for adapters of identifier properties and discriminators. Unlike JPA converters, a UserType in Hibernate can be an adapter for any kind of entity property. Because MonetaryAmount won’t be the type of an identifier property or discriminator, you won’t need it.
UserVersionType —This is an optional interface for adapters of version properties.
UserCollectionType —This rarely needed interface is used to implement custom collections. You have to implement it to persist a non- JDK collection and preserve additional semantics.
三、代码
1.
package org.jpwh.converter; import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.DynamicParameterizedType;
import org.jpwh.model.advanced.MonetaryAmount; import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Currency;
import java.util.Properties; public class MonetaryAmountUserType
implements CompositeUserType, DynamicParameterizedType { protected Currency convertTo; public void setParameterValues(Properties parameters) { /**
* You can access some dynamic parameters here, such as the
* name of the mapped columns, the mapped (entity) table, or even the
* annotations on the field/getter of the mapped property. We won't need
* them in this example though.
*/
ParameterType parameterType =
(ParameterType) parameters.get(PARAMETER_TYPE);
String[] columns = parameterType.getColumns();
String table = parameterType.getTable();
Annotation[] annotations = parameterType.getAnnotationsMethod(); /**
* We only use the <code>convertTo</code> parameter to
* determine the target currency when saving a value into the database.
* If the parameter hasn't been set, we default to US Dollar.
*/
String convertToParameter = parameters.getProperty("convertTo");
this.convertTo = Currency.getInstance(
convertToParameter != null ? convertToParameter : "USD"
);
} /**
* The method <code>returnedClass</code> adapts the given class, in this case
* <code>MonetaryAmount</code>.
*/
public Class returnedClass() {
return MonetaryAmount.class;
} /**
* Hibernate can enable some optimizations if it knows
* that <code>MonetaryAmount</code> is immutable.
*/
public boolean isMutable() {
return false;
} /**
* If Hibernate has to make a copy of the value, it will call
* this method. For simple immutable classes like <code>MonetaryAmount</code>,
* you can return the given instance.
*/
public Object deepCopy(Object value) {
return value;
} /**
* Hibernate calls <code>disassemble</code> when it stores a value in the global shared second-level
* cache. You need to return a <code>Serializable</code> representation. For <code>MonetaryAmount</code>,
* a <code>String</code> representation is an easy solution. Or, because <code>MonetaryAmount</code> is actually
* <code>Serializable</code>, you could return it directly.
*/
public Serializable disassemble(Object value,
SessionImplementor session) {
return value.toString();
} /**
* Hibernate calls this method when it reads the serialized
* representation from the global shared second-level cache. We create a
* <code>MonetaryAmount</code> instance from the <code>String</code>
* representation. Or, if have stored a serialized <code>MonetaryAmount</code>,
* you could return it directly.
*/
public Object assemble(Serializable cached,
SessionImplementor session, Object owner) {
return MonetaryAmount.fromString((String) cached);
} /**
* Called during <code>EntityManager#merge()</code> operations, you
* need to return a copy of the <code>original</code>. Or, if your value type is
* immutable, like <code>MonetaryAmount</code>, you can simply return the original.
*/
public Object replace(Object original, Object target,
SessionImplementor session, Object owner) {
return original;
} /**
* Hibernate will use value equality to determine whether the value
* was changed, and the database needs to be updated. We rely on the equality
* routine we have already written on the <code>MonetaryAmount</code> class.
*/
public boolean equals(Object x, Object y) {
return x == y || !(x == null || y == null) && x.equals(y);
} public int hashCode(Object x) {
return x.hashCode();
} /**
* Called to read the <code>ResultSet</code>, when a
* <code>MonetaryAmount</code> value has to be retrieved from the database.
* We take the <code>amount</code> and <code>currency</code> values as given
* in the query result, and create a new instance of <code>MonetaryAmount</code>.
*/
public Object nullSafeGet(ResultSet resultSet,
String[] names,
SessionImplementor session,
Object owner) throws SQLException { BigDecimal amount = resultSet.getBigDecimal(names[0]);
if (resultSet.wasNull())
return null;
Currency currency =
Currency.getInstance(resultSet.getString(names[1]));
return new MonetaryAmount(amount, currency);
} /**
* Called when a <code>MonetaryAmount</code> value has
* to be stored in the database. We convert the value to the target currency,
* then set the <code>amount</code> and <code>currency</code> on the
* provided <code>PreparedStatement</code>. (Unless the <code>MonetaryAmount</code>
* was <code>null</code>, in that case, we call <code>setNull()</code> to
* prepare the statement.)
*/
public void nullSafeSet(PreparedStatement statement,
Object value,
int index,
SessionImplementor session) throws SQLException { if (value == null) {
statement.setNull(
index,
StandardBasicTypes.BIG_DECIMAL.sqlType());
statement.setNull(
index + 1,
StandardBasicTypes.CURRENCY.sqlType());
} else {
MonetaryAmount amount = (MonetaryAmount) value;
// When saving, convert to target currency
MonetaryAmount dbAmount = convert(amount, convertTo);
statement.setBigDecimal(index, dbAmount.getValue());
statement.setString(index + 1, convertTo.getCurrencyCode());
}
} /**
* Here you can implement whatever currency conversion routine
* you need. For the sake of the example, we simply double the value so we
* can easily test if conversion was successful. You'll have to replace this
* code with a real currency converter in a real application. It's not a
* method of the Hibernate <code>UserType</code> API.
*/
protected MonetaryAmount convert(MonetaryAmount amount,
Currency toCurrency) {
return new MonetaryAmount(
amount.getValue().multiply(new BigDecimal(2)),
toCurrency
);
} public String[] getPropertyNames() {
return new String[]{"value", "currency"};
} public Type[] getPropertyTypes() {
return new Type[]{
StandardBasicTypes.BIG_DECIMAL,
StandardBasicTypes.CURRENCY
};
} public Object getPropertyValue(Object component,
int property) {
MonetaryAmount monetaryAmount = (MonetaryAmount) component;
if (property == 0)
return monetaryAmount.getValue();
else
return monetaryAmount.getCurrency();
} public void setPropertyValue(Object component,
int property,
Object value) {
throw new UnsupportedOperationException(
"MonetaryAmount is immutable"
);
} // ...
}
2.
@org.hibernate.annotations.TypeDefs({
@org.hibernate.annotations.TypeDef(
name = "monetary_amount_usd",
typeClass = MonetaryAmountUserType.class,
parameters = {@Parameter(name = "convertTo", value = "USD")}
),
@org.hibernate.annotations.TypeDef(
name = "monetary_amount_eur",
typeClass = MonetaryAmountUserType.class,
parameters = {@Parameter(name = "convertTo", value = "EUR")}
)
})
package org.jpwh.converter;
import org.hibernate.annotations.Parameter;
3.
package org.jpwh.model.advanced.usertype; import org.jpwh.model.advanced.MonetaryAmount; import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull; @Entity
public class Item { @Id
@GeneratedValue(generator = "ID_GENERATOR")
protected Long id; @NotNull
protected String name; @NotNull
@org.hibernate.annotations.Type(
type = "monetary_amount_usd"
)
@org.hibernate.annotations.Columns(columns = {
@Column(name = "BUYNOWPRICE_AMOUNT"),
@Column(name = "BUYNOWPRICE_CURRENCY", length = 3)
})
protected MonetaryAmount buyNowPrice; @NotNull
@org.hibernate.annotations.Type(
type = "monetary_amount_eur"
)
@org.hibernate.annotations.Columns(columns = {
@Column(name = "INITIALPRICE_AMOUNT"),
@Column(name = "INITIALPRICE_CURRENCY", length = 3)
})
protected MonetaryAmount initialPrice; public Long getId() {
return id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public MonetaryAmount getBuyNowPrice() {
return buyNowPrice;
} public void setBuyNowPrice(MonetaryAmount buyNowPrice) {
this.buyNowPrice = buyNowPrice;
} public MonetaryAmount getInitialPrice() {
return initialPrice;
} public void setInitialPrice(MonetaryAmount initialPrice) {
this.initialPrice = initialPrice;
} // ...
}
4.
package org.jpwh.model.advanced; import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Currency; /*
This value-typed class should be <code>java.io.Serializable</code>: When Hibernate stores entity
instance data in the shared second-level cache (see <a href="#Caching"/>), it <em>disassembles</em>
the entity's state. If an entity has a <code>MonetaryAmount</code> property, the serialized
representation of the property value will be stored in the second-level cache region. When entity
data is retrieved from the cache region, the property value will be deserialized and reassembled.
*/
public class MonetaryAmount implements Serializable { /*
The class does not need a special constructor, you can make it immutable, even with
<code>final</code> fields, as your code will be the only place an instance is created.
*/
protected final BigDecimal value;
protected final Currency currency; public MonetaryAmount(BigDecimal value, Currency currency) {
this.value = value;
this.currency = currency;
} public BigDecimal getValue() {
return value;
} public Currency getCurrency() {
return currency;
} /*
You should implement the <code>equals()</code> and <code>hashCode()</code>
methods, and compare monetary amounts "by value".
*/
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MonetaryAmount)) return false; final MonetaryAmount monetaryAmount = (MonetaryAmount) o; if (!value.equals(monetaryAmount.value)) return false;
if (!currency.equals(monetaryAmount.currency)) return false; return true;
} public int hashCode() {
int result;
result = value.hashCode();
result = 29 * result + currency.hashCode();
return result;
} /*
You will need a <code>String</code> representation of a monetary
amount. Implement the <code>toString()</code> method and a static method to
create an instance from a <code>String</code>.
*/
public String toString() {
return getValue() + " " + getCurrency();
} public static MonetaryAmount fromString(String s) {
String[] split = s.split(" ");
return new MonetaryAmount(
new BigDecimal(split[0]),
Currency.getInstance(split[1])
);
}
}
5.
JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-007UserTypes的用法(@org.hibernate.annotations.Type、@org.hibernate.annotations.TypeDefs、CompositeUserType、DynamicParameterizedType、、、)的更多相关文章
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-006类型转换器( @Converter(autoApply = true) 、type="converter:qualified.ConverterName" )
一.结构 二.代码 1. package org.jpwh.model.advanced; import java.io.Serializable; import java.math.BigDecim ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-001Mapping basic properties(@Basic、@Access、access="noop"、@Formula、@ColumnTransformer、@Generated、 @ColumnDefaul、@Temporal、@Enumerated)
一.简介 在JPA中,默认所有属性都会persist,属性要属于以下3种情况,Hibernate在启动时会报错 1.java基本类型或包装类 2.有注解 @Embedded 3.有实现java.io. ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-005控制类型映射(Nationalized、@LOB、@org.hibernate.annotations.Type)
一.简介 1. 2. 3. 4. to override this default mapping. The JPA specification has a convenient shortcut a ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-004嵌套组件的注解AttributeOverrides
一.数据库 二.代码 1. package org.jpwh.model.advanced; import javax.persistence.AttributeOverride; import ja ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-003使用@AttributeOverrides
Each @AttributeOverride for a component property is “complete”: any JPA or Hibernate annotation on t ...
- JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-002使用@Embeddable
一.数据库 二.代码 1. package org.jpwh.model.simple; import javax.persistence.Column; import javax.persisten ...
- JavaPersistenceWithHibernate第二版笔记-第四章-Mapping persistent classes-003映射实体时的可选操作(<delimited-identifiers/>、PhysicalNamingStrategy、PhysicalNamingStrategyStandardImpl、、、)
一.自定义映射的表名 1. @Entity @Table(name = "USERS") public class User implements Serializable { / ...
- JavaPersistenceWithHibernate第二版笔记-第六章-Mapping inheritance-002Table per concrete class with implicit polymorphism(@MappedSuperclass、@AttributeOverride)
一.结构 二.代码 1. package org.jpwh.model.inheritance.mappedsuperclass; import javax.persistence.MappedSup ...
- JavaPersistenceWithHibernate第二版笔记-第六章-Mapping inheritance-003Table per concrete class with unions(@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)、<union-subclass>)
一.代码 1. package org.jpwh.model.inheritance.tableperclass; import org.jpwh.model.Constants; import ja ...
随机推荐
- iOS 进阶 第十八天(0423)
0423 - GCD( Grand Central Dispatch) block复习 请问,图中输出结果是多少?为什么? 答:结果是10.因为在定义block的时候,block会把它前面的要用到的变 ...
- 转载 SQL Server 2008 R2 事务与隔离级别实例讲解
原文:http://blog.itpub.net/13651903/viewspace-1082730/ 一.事务简介 SQL Server的6个隔离级别中有5个是用于隔离事务的,它们因而被称作事务隔 ...
- UITableView基本使用和cell的属性
在ios的UI中UITableView是个常用且强大的控件 基本使用: 1>设置代理,一般把控制器设为代理:self.tableView.delegate = self; 2>遵守代理的协 ...
- mobiscroll 控件的使用(手机端日历控件)
先上一张图吧: 控件的下载地址:http://www.kuitao8.com/20140604/2615.shtml 文档API地址:http://docs.mobiscroll.com/2-13-2 ...
- Careercup - Microsoft面试题 - 5684901156225024
2014-05-10 23:45 题目链接 原题: Arrange the numbers in an array in alternating order. For example if the a ...
- android开发 WriteUTF与readUTF 原理
今晚上写代码玩,用到java.io.RandomAccessFile.writeUTF(String)函数,而文件默认保存为gbk,显然是乱码.突然想起来去看看存储编码规则,就去找了些文章了解writ ...
- JavaScript 闭包详解
一.Javascript闭包的用途 事实上,通过使用闭包,我们可以做很多事情.比如模拟面向对象的代码风格:更优雅,更简洁的表达出代码:在某些方面提升代码的执行效率. 1.匿名自执行函数 我们知道所有的 ...
- LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面
// test20.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> #include< ...
- [bzoj 3226]校门外的区间
题意 输出最后的集合 题解 校门外的树会做吧 区间知道是什么东西吧 校门外的区间会做了吧 昨天做个大线段树没做出来,今天做个小线段树压压惊 py一下输入数据,然后操作变成: U 区间涂1 I 两侧 ...
- Phyre LCUE with YEBIS cause issues about GS
when LCUE enabled in phyreEngine when Yebis integrated and render there are two mainloopdraws in one ...