사용자 도구

사이트 도구


java:jpa:converter

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

양쪽 이전 판 이전 판
다음 판
이전 판
java:jpa:converter [2018/07/11 14:43]
kwon37xi
java:jpa:converter [2022/11/18 15:05] (현재)
kwon37xi [변환 클래스에 equals & hashCode 구현 필수]
줄 3: 줄 3:
   * [[java:hibernate:usertype|Hibernate User Type]] 보다 간결하게 엔티티 필드 객체와 DB 타입간 변환이 가능하다. 물론 기능은 다소 부족할 수 있으나 대부분의 경우를 만족시켜줄 수 있다.   * [[java:hibernate:usertype|Hibernate User Type]] 보다 간결하게 엔티티 필드 객체와 DB 타입간 변환이 가능하다. 물론 기능은 다소 부족할 수 있으나 대부분의 경우를 만족시켜줄 수 있다.
   * [[http://www.baeldung.com/jpa-attribute-converters|JPA Attribute Converters | Baeldung]]   * [[http://www.baeldung.com/jpa-attribute-converters|JPA Attribute Converters | Baeldung]]
 +  * ''@Id'' 컬럼에 대해서는 Converter 사용이 불가하다(JPA 명세에 불가하다고 나옴). [[java:hibernate:usertype|Hibernate User Type]] 사용해야 할 것 같다.
 <code java> <code java>
 @Converter @Converter
-public class PersonNameConverter implements +public class PersonNameConverter implements AttributeConverter<PersonName, String> {
-  AttributeConverter<PersonName, String> { +
-  +
-    private static final String SEPARATOR = ", ";+
    
     @Override     @Override
     public String convertToDatabaseColumn(PersonName personName) {     public String convertToDatabaseColumn(PersonName personName) {
-        if (personName == null) { +        // object to DB column 구현
-            return null; +
-        } +
-  +
-        StringBuilder sb = new StringBuilder(); +
-        if (personName.getSurname() != null && !personName.getSurname() +
-            .isEmpty()) { +
-            sb.append(personName.getSurname()); +
-            sb.append(SEPARATOR); +
-        } +
-  +
-        if (personName.getName() != null +
-          && !personName.getName().isEmpty()) { +
-            sb.append(personName.getName()); +
-        } +
-  +
-        return sb.toString();+
     }     }
    
     @Override     @Override
     public PersonName convertToEntityAttribute(String dbPersonName) {     public PersonName convertToEntityAttribute(String dbPersonName) {
-        if (dbPersonName == null || dbPersonName.isEmpty()) { +       // DB column to object 구현
-            return null; +
-        +
-  +
-        String[] pieces = dbPersonName.split(SEPARATOR); +
-  +
-        if (pieces == null || pieces.length == 0) { +
-            return null; +
-        } +
-  +
-        PersonName personName = new PersonName();         +
-        String firstPiece = !pieces[0].isEmpty() ? pieces[0] : null; +
-        if (dbPersonName.contains(SEPARATOR)) { +
-            personName.setSurname(firstPiece); +
-  +
-            if (pieces.length >= 2 && pieces[1] != null +
-              && !pieces[1].isEmpty()) { +
-                personName.setName(pieces[1]); +
-            } +
-        } else { +
-            personName.setName(firstPiece); +
-        } +
-  +
-        return personName; +
-    }+
 } }
  
줄 70: 줄 27:
 } }
 </code> </code>
 +
 +===== 변환 클래스에 equals & hashCode 구현 필수 =====
 +
 +  * ''AttributeConverter''의 컨버팅 대상이 되는 클래스에 **''equals'', ''hashCode'' 메소드를 명확히 구현할 것.**
 +  * [[java:hibernate|Hibernate]]의 경우, Dirty Checking 시에 최초 생성된 객체를 복사해서 따로 저장하고 이후에 복사본과 마지막 상태를 ''equals'' 로 비교한다. 따라서 ''equals/hashCode''가 복사시마다 달라지는 경우에 문제 소지가 있다.
 +  * 이때 첫 값과 두번째 값의 ''equals''를 보고서 dirty checking 을 하는데, ''equals''가 제대로 구현 안돼 있으면 ''false''가 나오고 그로인해 entity 전체에 대한 update 가 발생한다.
 +  * 따라서 Java 기본형들이 아닌 custom class 로 convert 할 경우에는 필히 ''equals''/''hashCode''를 구현해야 한다. 그렇지 않으면 모르는 사이에 지속적으로 update가 발생하게 된다.
 +  * [[https://stackoverflow.com/questions/47285684/hibernate-springdata-incorrect-dirty-check-on-field-with-attributeconverter|java - Hibernate/SpringData : Incorrect dirty check on field with AttributeConverter - Stack Overflow]]
 +  * [[https://medium.com/@paul.klingelhuber/hibernate-dirty-checking-with-converted-attributes-1b6d1cd27f68|Hibernate Dirty-Checking with Converted Attributes | by Paul Klingelhuber | Medium]]
 +
 +
 +===== 잘못된 Colum Type 매핑 =====
 +  * AttributeConverter 를 사용하여 String, Number 같은 다소 광의의 타입을 명시적 비즈니스 도메인 타입으로 매핑했을 때(예: ISBN), 보통 해당 타입이 ''Serializable''을 구현하면서 Hibernate가 무조건 ''VARBINARY''로 매핑하는 버그가 있다(현재 5.2.x 버전도 마찬가지)
 +  * 이때 [[https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/type/StandardBasicTypes.java|StandardBasicTypes.java]]에 나온 타입들을 명시적으로 지정해주면 된다.
 +
 +<code java>
 +@Convert(converter=ISBNConverter.class)
 +@org.hibernate.annotations.Type(type="string")
 +private ISBN isbn;
 +</code>
 +
java/jpa/converter.1531287803.txt.gz · 마지막으로 수정됨: 2018/07/11 14:43 저자 kwon37xi