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 ...
随机推荐
- R 语言中文乱码问题
R 语言似乎在WINDOWS平台上对中文的支持不是特别好,似乎是3.1.2的一个BUG. 目前我研究出了一个临时解决方案,你可以将代码编写成一个函数,从而在调用的过程中不必如下繁琐: 1. 先将本地语 ...
- 如何破解UltraEdit
在断网的前提下,软件->帮助->注册->激活->脱机激活—>用户和密码随便输入->还有两个空着,就是该用注册机激活了. 打开注册机->输入ULtredit的自 ...
- Quartus13.0破解方法
一定要按照步骤顺序才能破解,这里很关键 1.下载和打开Quartus II破解器,选择“应用”,选择“是”,找到bin(64位系统是bin64)目录下的sys_cpt.dll,“打开” 2.然后将li ...
- PB数据类型转换表
数据类型转换表 MICROSOFT PB(16Bit) PB(32Bit) Bool Boolean ...
- [收藏]Spring Security中的ACL
ACL即访问控制列表(Access Controller List),它是用来做细粒度权限控制所用的一种权限模型.对ACL最简单的描述就是两个业务员,每个人只能查看操作自己签的合同,而不能看到对方的合 ...
- 制作C/C++动态链接库(dll)若干注意事项
一.C\C++ 运行时库编译选项简单说明 问题:我的dll别人没法用 运行时库是个很复杂的东西,作为开发过程中dll制作需要了解的一部分,这里主要简单介绍一下如何选择编译选项. 在我们的开发过程中时常 ...
- Java令牌生成器
package Token; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; im ...
- merry Christmas
圣诞节的来历 圣诞节这个名称是基督弥撒的缩写. 弥撒是教会的一种礼拜仪式. 1.耶诞节是一个宗节,我们把它当作耶苏的诞辰来庆祝,因而又名耶诞节.这一天,世界所有的基督教会都举行特别的礼拜仪式.但是有很 ...
- 浏览器不支持HTML5
有些浏览器并不支持HTML5中的新增元素,如IE8或更早版本.想要应用样式,可以头部标记<head>中加入下面JavaScript代码 <html> <head> ...
- WinForm-利用Anchor和Dock属性缩放控件
转自:http://www.cnblogs.com/tianzhiliang/articles/2144692.html 有一点让许多刚接触WinForms编程的开发者感到很棘手,就是在用户调整各种控 ...