JavaPersistenceWithHibernate第二版笔记-第五章-Mapping value types-006类型转换器( @Converter(autoApply = true) 、type="converter:qualified.ConverterName" )

一、结构

二、代码

1.

 1 package org.jpwh.model.advanced;
 2 
 3 import java.io.Serializable;
 4 import java.math.BigDecimal;
 5 import java.util.Currency;
 6 
 7 /* 
 8    This value-typed class should be <code>java.io.Serializable</code>: When Hibernate stores entity
 9    instance data in the shared second-level cache (see <a href="#Caching"/>), it <em>disassembles</em>
10    the entity's state. If an entity has a <code>MonetaryAmount</code> property, the serialized
11    representation of the property value will be stored in the second-level cache region. When entity
12    data is retrieved from the cache region, the property value will be deserialized and reassembled.
13  */
14 public class MonetaryAmount implements Serializable {
15 
16     /*
17  The class does not need a special constructor, you can make it immutable, even with
18         <code>final</code> fields, as your code will be the only place an instance is created.
19      */
20     protected final BigDecimal value;
21     protected final Currency currency;
22 
23     public MonetaryAmount(BigDecimal value, Currency currency) {
24         this.value = value;
25         this.currency = currency;
26     }
27 
28     public BigDecimal getValue() {
29         return value;
30     }
31 
32     public Currency getCurrency() {
33         return currency;
34     }
35 
36     /*
37  You should implement the <code>equals()</code> and <code>hashCode()</code>
38         methods, and compare monetary amounts "by value".
39      */
40     public boolean equals(Object o) {
41         if (this == o) return true;
42         if (!(o instanceof MonetaryAmount)) return false;
43 
44         final MonetaryAmount monetaryAmount = (MonetaryAmount) o;
45 
46         if (!value.equals(monetaryAmount.value)) return false;
47         if (!currency.equals(monetaryAmount.currency)) return false;
48 
49         return true;
50     }
51 
52     public int hashCode() {
53         int result;
54         result = value.hashCode();
55         result = 29 * result + currency.hashCode();
56         return result;
57     }
58 
59     /*
60  You will need a <code>String</code> representation of a monetary
61         amount. Implement the <code>toString()</code> method and a static method to
62         create an instance from a <code>String</code>.
63      */
64     public String toString() {
65         return getValue() + " " + getCurrency();
66     }
67 
68     public static MonetaryAmount fromString(String s) {
69         String[] split = s.split(" ");
70         return new MonetaryAmount(
71             new BigDecimal(split[0]),
72             Currency.getInstance(split[1])
73         );
74     }
75 }

 

2.

 1 package org.jpwh.converter;
 2 
 3 import org.jpwh.model.advanced.MonetaryAmount;
 4 
 5 import javax.persistence.AttributeConverter;
 6 import javax.persistence.Converter;
 7 
 8 @Converter(autoApply = true) // Default for MonetaryAmount properties
 9 public class MonetaryAmountConverter
10     implements AttributeConverter<MonetaryAmount, String> {
11 
12     @Override
13     public String convertToDatabaseColumn(MonetaryAmount monetaryAmount) {
14         return monetaryAmount.toString();
15     }
16 
17     @Override
18     public MonetaryAmount convertToEntityAttribute(String s) {
19         return MonetaryAmount.fromString(s);
20     }
21 }

 

3.

 1 package org.jpwh.model.advanced.converter;
 2 
 3 
 4 import org.jpwh.converter.MonetaryAmountConverter;
 5 import org.jpwh.model.advanced.MonetaryAmount;
 6 
 7 import javax.persistence.Column;
 8 import javax.persistence.Convert;
 9 import javax.persistence.Entity;
10 import javax.persistence.GeneratedValue;
11 import javax.persistence.Id;
12 import javax.validation.constraints.NotNull;
13 import java.util.Date;
14 
15 @Entity
16 public class Item {
17 
18     @Id
19     @GeneratedValue(generator = "ID_GENERATOR")
20     protected Long id;
21 
22     @NotNull
23     protected String name;
24 
25     @NotNull
26     @Convert( // Optional, autoApply is enabled
27         converter = MonetaryAmountConverter.class,
28         disableConversion = false)
29     @Column(name = "PRICE", length = 63)
30     protected MonetaryAmount buyNowPrice;
31 
32     @NotNull
33     protected Date createdOn = new Date();
34 
35     public Long getId() {
36         return id;
37     }
38 
39     public String getName() {
40         return name;
41     }
42 
43     public void setName(String name) {
44         this.name = name;
45     }
46 
47     public MonetaryAmount getBuyNowPrice() {
48         return buyNowPrice;
49     }
50 
51     public void setBuyNowPrice(MonetaryAmount buyNowPrice) {
52         this.buyNowPrice = buyNowPrice;
53     }
54 
55     // ...
56 }

 

4.

 1 package org.jpwh.model.advanced.converter;
 2 
 3 abstract public class Zipcode {
 4 
 5     protected String value;
 6 
 7     public Zipcode(String value) {
 8         this.value = value;
 9     }
10 
11     public String getValue() {
12         return value;
13     }
14 
15     @Override
16     public boolean equals(Object o) {
17         if (this == o) return true;
18         if (o == null || getClass() != o.getClass()) return false;
19         Zipcode zipcode = (Zipcode) o;
20         return value.equals(zipcode.value);
21     }
22 
23     @Override
24     public int hashCode() {
25         return value.hashCode();
26     }
27 }

 

5.

 1 package org.jpwh.converter;
 2 
 3 import org.jpwh.model.advanced.converter.GermanZipcode;
 4 import org.jpwh.model.advanced.converter.SwissZipcode;
 5 import org.jpwh.model.advanced.converter.Zipcode;
 6 
 7 import javax.persistence.AttributeConverter;
 8 import javax.persistence.Converter;
 9 
10 @Converter
11 public class ZipcodeConverter
12     implements AttributeConverter<Zipcode, String> {
13 
14     @Override
15     public String convertToDatabaseColumn(Zipcode attribute) {
16         return attribute.getValue();
17     }
18 
19     @Override
20     public Zipcode convertToEntityAttribute(String s) {
21         if (s.length() == 5)
22             return new GermanZipcode(s);
23         else if (s.length() == 4)
24             return new SwissZipcode(s);
25 
26         // If you get to this point, you should consider
27         // cleaning up your database... or you can create
28         // an InvalidZipCode subclass and return it here.
29 
30         throw new IllegalArgumentException(
31             "Unsupported zipcode in database: " + s
32         );
33     }
34 }

 

6.

1 package org.jpwh.model.advanced.converter;
2 
3 public class GermanZipcode extends Zipcode {
4 
5     public GermanZipcode(String value) {
6         super(value);
7     }
8 }

 

7.

1 package org.jpwh.model.advanced.converter;
2 
3 public class SwissZipcode extends Zipcode {
4 
5     public SwissZipcode(String value) {
6         super(value);
7     }
8 }

8.

 1 package org.jpwh.model.advanced.converter;
 2 
 3 import org.jpwh.converter.ZipcodeConverter;
 4 import org.jpwh.model.Constants;
 5 
 6 import javax.persistence.Convert;
 7 import javax.persistence.Entity;
 8 import javax.persistence.GeneratedValue;
 9 import javax.persistence.Id;
10 import javax.persistence.Table;
11 import javax.validation.constraints.NotNull;
12 import java.io.Serializable;
13 
14 @Entity
15 @Table(name = "USERS")
16 public class User implements Serializable {
17 
18     @Id
19     @GeneratedValue(generator = Constants.ID_GENERATOR)
20     protected Long id;
21 
22     @NotNull
23     protected String username;
24 
25     // Group multiple attribute conversions with @Converts
26     @Convert(
27         converter = ZipcodeConverter.class,
28         attributeName = "zipcode" // Or "city.zipcode" for nested embeddables
29     )
30     protected Address homeAddress;
31 
32     public Long getId() {
33         return id;
34     }
35     public String getUsername() {
36         return username;
37     }
38 
39     public void setUsername(String username) {
40         this.username = username;
41     }
42 
43     public Address getHomeAddress() {
44         return homeAddress;
45     }
46 
47     public void setHomeAddress(Address homeAddress) {
48         this.homeAddress = homeAddress;
49     }
50 
51     // ...
52 }

 

9.

 1 package org.jpwh.model.advanced.converter;
 2 
 3 import javax.persistence.Column;
 4 import javax.persistence.Embeddable;
 5 import javax.validation.constraints.NotNull;
 6 
 7 @Embeddable
 8 public class Address {
 9 
10     @NotNull
11     @Column(nullable = false)
12     protected String street;
13 
14     @NotNull
15     @Column(nullable = false, length = 5)
16     protected Zipcode zipcode;
17 
18     @NotNull
19     @Column(nullable = false)
20     protected String city;
21 
22     protected Address() {
23     }
24 
25     public Address(String street, Zipcode zipcode, String city) {
26         this.street = street;
27         this.zipcode = zipcode;
28         this.city = city;
29     }
30 
31     public String getStreet() {
32         return street;
33     }
34 
35     public void setStreet(String street) {
36         this.street = street;
37     }
38 
39     public Zipcode getZipcode() {
40         return zipcode;
41     }
42 
43     public void setZipcode(Zipcode zipcode) {
44         this.zipcode = zipcode;
45     }
46 
47     public String getCity() {
48         return city;
49     }
50 
51     public void setCity(String city) {
52         this.city = city;
53     }
54 }

 

也可以转换集合,If several @Convert annotations are required on a single embedded property, to convert several attributes of the Address , for example, you can group them within an @Converts annotation. You can also apply converters to values of collections and maps, if their values and/or keys are of basic or embeddable type. For example, you can add the @Convert annotation on a persistent Set<Zipcode> . We’ll show you how

to map persistent collections later, with @ElementCollection , in chapter 7.
For persistent maps, the attributeName option of the @Convert annotation has some special syntax:

 On a persistent Map<Address, String> , you can apply a converter for the zipcode property of each map key with the attribute name key.zipcode .
 On a persistent Map<String, Address> , you can apply a converter for the zipcode property of each map value with the attribute name value.zipcode .
 On a persistent Map<Zipcode, String> , you can apply a converter for the key of each map entry with the attribute name key .
 On a persistent Map<String, Zipcode> , you can apply a converter for the value of each map entry by not setting any attributeName .
As before, the attribute name can be a dot-separated path if your embeddable classes are nested; you can write key.city.zipcode to reference the zipcode property of the City class, in a composition with the Address class.
Some limitations of the JPA converters are as follows:
 You can’t apply them to identifier or version properties of an entity.
 You shouldn’t apply a converter on a property mapped with @Enumerated or @Temporal , because these annotations already declare what kind of conversion has to occur. If you want to apply a custom converter for enums or date/time properties, don’t annotate them with @Enumerated or @Temporal .
 You can apply a converter to a property mapping in an hbm.xml file, but you have to prefix the name: type="converter:qualified.ConverterName" .

posted @ 2016-04-07 17:38  shamgod  阅读(1573)  评论(0)    收藏  举报
haha