一、结构

二、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、、、)的更多相关文章

  1. 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 ...

  2. 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. ...

  3. 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 ...

  4. JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-004嵌套组件的注解AttributeOverrides

    一.数据库 二.代码 1. package org.jpwh.model.advanced; import javax.persistence.AttributeOverride; import ja ...

  5. JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-003使用@AttributeOverrides

    Each @AttributeOverride for a component property is “complete”: any JPA or Hibernate annotation on t ...

  6. JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-002使用@Embeddable

    一.数据库 二.代码 1. package org.jpwh.model.simple; import javax.persistence.Column; import javax.persisten ...

  7. JavaPersistenceWithHibernate第二版笔记-第四章-Mapping persistent classes-003映射实体时的可选操作(<delimited-identifiers/>、PhysicalNamingStrategy、PhysicalNamingStrategyStandardImpl、、、)

    一.自定义映射的表名 1. @Entity @Table(name = "USERS") public class User implements Serializable { / ...

  8. JavaPersistenceWithHibernate第二版笔记-第六章-Mapping inheritance-002Table per concrete class with implicit polymorphism(@MappedSuperclass、@AttributeOverride)

    一.结构 二.代码 1. package org.jpwh.model.inheritance.mappedsuperclass; import javax.persistence.MappedSup ...

  9. 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 ...

随机推荐

  1. 56.ISE综合,在chipscope信号列表看不到

    代码写好后,进行逻辑综合,在chipscope上添加被触发的信号时,发现有些在信号列表里看不到,这是因为这些信号没有参与到逻辑电路设计中,产生不想关的电路,综合器会默认优化资源. 还有一种情况是,对于 ...

  2. python三级菜单

    #-*- coding:utf-8 -*-#Author:gxli #一级菜单项def menu(): #遍历字典dic一级菜单 print('-----------一级菜单------------- ...

  3. STL学习三:deque容器

    1.Deque简介 deque是“double-ended queue”的缩写,和vector一样都是STL的容器,deque是双端数组,而vector是单端的. deque在接口上和vector非常 ...

  4. 用C++编写一个随机产生多个两位数四则运算式子的简单程序

    一 设计思想: 1.首先可以想到一个四则运算式子的组成:两个运算数和一个运算符: 2.两个运算数的随机由调用随机函数产生,其中可以设定运算数的范围: 3.一个运算符的随机产生可以分为加减乘除四种情况, ...

  5. 受限玻尔兹曼机RBM—简易详解

  6. struts2标签详解

    struts2标签讲解 要使用Struts2的标签,只需要在JSP页面添加如下一行定义即可:<%@ taglib prefix="s" uri="/struts-t ...

  7. kernel nf_conntrack: table full, dropping packet[转载]

    http://blog.yorkgu.me/2012/02/09/kernel-nf_conntrack-table-full-dropping-packet/ 综合:ip_conntrack就是li ...

  8. Mysql高级之存储过程

    参考地址1:http://www.2cto.com/database/201411/350819.html 参考地址2:http://www.jb51.net/article/39471.htm my ...

  9. The income statement

    The income statement measures performance over some period  of time,usually a quarter or a year.The ...

  10. css3 的content 属性

    content属性想必大家都熟悉了,一般结合伪类一起使用,表示显示的内容 例如:.box:before{content:"hello";width:100px;line-heigh ...