一、结构

二、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. java判断某个字符串包含某个字符串的个数

    /** * 判断str1中包含str2的个数 * @param str1 * @param str2 * @return counter */ public static int countStr(S ...

  2. 随笔 planetest

    Camera跟随物体: import Scripts包,Component中的camera control会有smooth follow脚本,添加到Main Camera中,在脚本的target属性中 ...

  3. LeetCode Shell Problems

    195. Tenth Line -- 第十行 How would you print just the 10th line of a file? Solution: awk 'NR==10' file ...

  4. mobiscroll 控件的使用(手机端日历控件)

    先上一张图吧: 控件的下载地址:http://www.kuitao8.com/20140604/2615.shtml 文档API地址:http://docs.mobiscroll.com/2-13-2 ...

  5. C#委托详解(1):什么是委托

    本系列文章将详细探讨C#中的委托,列举其主要的实现方式,并分析其在设计层面和编码层面带来的好处,最后会讨论其安全性和执行效率等. 什么是委托? 委托是寻址方法的.NET版本,使用委托可以将方法作为参数 ...

  6. 自定义异常时如何定义checked异常和unchecked异常

    When defining your own exception type, study the existing exception classes in the Java API and try ...

  7. Servlet主要的作用

    1,收集Request传递过来的参数: 2,把这些参数组织成模型需要的类型: 3,调用模型进行逻辑功能处理: 4,选择下一个页面,先准备好一个页面需要的数据,然后转向下一个页面.

  8. hdu 2853 Assignment KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2853 Last year a terrible earthquake attacked Sichuan ...

  9. 【CodeForces】【311E】Biologist

    网络流/最大权闭合图 题目:http://codeforces.com/problemset/problem/311/E 嗯这是最大权闭合图中很棒的一道题了- 能够1A真是开心-也是我A掉的第一道E题 ...

  10. 【BZOJ】【3282】Tree

    LCT 喜闻乐见的Link-Cut-Tree…… srO zyf http://www.cnblogs.com/zyfzyf/p/4149109.html 目测我是第222个?………………不要在意这些 ...