2011-08-28 41 views
15

Có cách nào để ánh xạ các đối tượng giá trị không thay đổi như địa chỉ email bằng JPA không?Đối tượng giá trị không thể thay đổi và JPA

@Immutable 
@Embeddable 
public final class EmailAddress { 
    private final String value; 

    public EmailAddress(String value) { 
     this.value = value; 
    } 

    public String getValue() { 
     return value; 
    } 

    @Override 
    public boolean equals(Object o) { 
     if (this == o) return true; 
     if (o == null || getClass() != o.getClass()) return false; 
     EmailAddress that = (EmailAddress) o; 
     return value.equals(that.value); 
    } 

    @Override 
    public int hashCode() { 
     return value.hashCode(); 
    } 
} 

Bây giờ tôi có được ngoại lệ về tổ chức tiết kiệm

org.hibernate.InstantiationException: No default constructor for entity: com.domain.EmailAddress 
    org.hibernate.tuple.PojoInstantiator.instantiate(PojoInstantiator.java:107) 
    org.hibernate.tuple.component.AbstractComponentTuplizer.instantiate(AbstractComponentTuplizer.java:102) 
    org.hibernate.type.ComponentType.instantiate(ComponentType.java:515) 
    org.hibernate.type.ComponentType.deepCopy(ComponentType.java:434) 
    org.hibernate.type.TypeHelper.deepCopy(TypeHelper.java:68) 
    org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:302) 
    org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:203) 
    org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:129) 
    org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69) 
    org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:179) 
    org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) 
    org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) 
    org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:808) 
    org.hibernate.impl.SessionImpl.persist(SessionImpl.java:782) 
    org.hibernate.impl.SessionImpl.persist(SessionImpl.java:786) 
    org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:672) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    java.lang.reflect.Method.invoke(Method.java:597) 
    org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) 
    $Proxy25.persist(Unknown Source) 
    org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:360) 
    sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    java.lang.reflect.Method.invoke(Method.java:597) 
    org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:368) 
    org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:349) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
    org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
    org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
    $Proxy26.save(Unknown Source) 
    com.controller.UserController.create(UserController.java:64) 

Tôi muốn sử dụng các trường chính thức và ngủ đông như thực hiện JPA.

Trả lời

13

Bạn thắng' t có thể làm điều đó bằng cách sử dụng chú thích JPA tiêu chuẩn và đối tượng có thể nhúng, vì đối tượng sẽ phải được tạo bằng cách sử dụng hàm tạo mặc định và giá trị được đặt qua phản ánh.

Tuy nhiên, bạn có thể sử dụng loại tùy chỉnh Hibernate. Đọc this part of the Hibernate reference documentation, trong đó có một ví dụ Money loại, được khởi tạo bằng cách sử dụng một hàm tạo với các đối số và do đó có thể không thay đổi.

+0

Cảm ơn rất nhiều. Nó hoạt động hoàn hảo. –

3

Để JPA có thể tạo đối tượng qua phản xạ, bạn phải có hàm tạo mặc định nhưng không cần phải công khai. Tôi cũng muốn giữ cho các trường của tôi cuối cùng, nhưng điều này có thể quá hạn chế để phản ánh - bạn sẽ phải thử.

tôi muốn đề nghị thả modifier lĩnh vực cuối cùng và thêm một constructor mặc định riêng với một lời nhận xét ngắn (vì vậy bạn vẫn biết tại sao điều đó không-op constructor là có vào tuần tới):

public final class EmailAddress { 
    private String value; // no final modifier 

    private EmailAddress() { 
     // for JPA 
    } 

    public EmailAddress(String value) { 
     this.value = value; 
    } 
... 
} 
+0

Cảm ơn. Nhưng tôi hy vọng có cái tốt hơn) –

+0

Một thử nghiệm nhanh tôi đã cho phép tôi thiết lập các trường cuối cùng riêng tư thông qua sự phản chiếu - vì vậy bạn có thể có 'giá trị String cuối cùng riêng;' và trong hàm dựng mặc định làm 'this.value = null' - - nhưng tài liệu Hibernate đề xuất giữ lại các công cụ sửa đổi cuối cùng (cũng cho lớp) để bật proxy/tải chậm: http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html/persistent -classes.html # persistent-classes-pojo-final –

+0

Tôi nghĩ rằng đó sẽ là giải pháp nhanh chóng. Nhưng tôi thích trình bày rõ ràng hơn về phát triển EE. –

7

Có lẽ giải pháp đơn giản nhất hoạt động với một số phiên bản cũ hơn như 3,5 của Hibernate là triển khai org.hibernate.usertype.UserType. Có khá một vài phương pháp trong đó nhưng đối với loại không thay đổi, bạn có thể giải nén hầu hết trong số họ để cha chung:

package com.acme; 

import java.io.Serializable; 

import org.hibernate.usertype.UserType; 

public abstract class AbstractImmutableType 
    implements UserType { 

public AbstractImmutableType() { 
    super(); 
} 

public boolean isMutable() { 
    return false; 
} 

public Serializable disassemble(Object value) { 
    return (Serializable) value; 
} 

public Object assemble(Serializable cached, Object owner) { 
    return cached; 
} 

public Object deepCopy(Object value) { 
    return value; 
} 

public Object replace(Object original, Object target, 
    Object owner) { 
    return original; 
} 

public boolean equals(Object x, Object y) { 
    if (x != null && y != null) { 
    return x.equals(y); 
    } 
    // Two nulls are equal as well 
    return x == null && y == null; 
} 

public int hashCode(Object x) { 
    if (x != null) { 
    return x.hashCode(); 
    } 
    return 0; 
} 
} 

Và bạn có thể sử dụng nó như thế này:

package com.acme; 

import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Types; 

public class CurrencyType extends AbstractImmutableType { 

public static final String TYPE = "com.acme.CurrencyType"; 

private static final int[] SQL_TYPES = { 
    Types.VARCHAR 
}; 

public CurrencyType() { 
    super(); 
} 

public Object nullSafeGet(ResultSet rs, String[] names, 
    Object owner) throws SQLException { 
    String value = rs.getString(names[0]); 
    if (rs.wasNull()) { 
    return null; 
    } 
    return Currency.valueOf(value); 
} 

public void nullSafeSet(PreparedStatement st, Object value, 
    int index) throws SQLException { 
    if (value != null) { 
    st.setString(index, ((Currency)value).getCode()); 
    } else { 
    st.setNull(index, SQL_TYPES[0]); 
    } 
} 

public Class<?> returnedClass() { 
    return Currency.class; 
} 

public int[] sqlTypes() { 
    return SQL_TYPES; 
} 
} 

Còn giải thích cho mã này bạn có thể tìm thấy here

+0

Cảm ơn. Tôi sẽ xem xét. –

Các vấn đề liên quan