不可变值对象和 JPA
有没有办法使用 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();
}
}
现在我在实体保存时遇到异常,
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)
我想使用最终字段和 hibernate 作为 JPA 实现。
Is there way to map immutable Value objects like email address using 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();
}
}
Now I get exception on entity save
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)
I want use final fields and hibernate as JPA implementation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
可能适用于较旧版本(例如 Hibernate 3.5)的最简单的解决方案是实现 org.hibernate.usertype.UserType。
其中有很多方法,但对于不可变类型,您可以将其中大部分提取到公共超类:
您可以像这样使用它:
您可以找到此代码的详细说明 此处
Probably the easiest solution which works with a little older versions like 3.5 of Hibernate is to implement org.hibernate.usertype.UserType.
There is quite a few methods in it but for immutable types you can extract most of them to common superclass:
And you can use it like this:
Longer explanation for this code you can find here
为了使 JPA 能够通过反射创建对象,您必须有一个默认构造函数,但它不必是公共的。我也喜欢将我的字段保留为最终状态,但这对于反思来说可能限制太多——你必须尝试一下。
我建议删除最终字段修饰符并添加一个带有简短注释的私有默认构造函数(这样您仍然知道为什么下周会出现无操作构造函数):
For JPA to be able to create objects via reflection, you have to have a default constructor, but it doesn't have to be public. I also like to keep my fields final, but this might be too restrictive for reflection -- you'll have to try.
I'd suggest dropping the final field modifier and adding a private default constructor with a short comment (so you still know why that no-op constructor is there next week):
您将无法使用标准 JPA 注释和可嵌入对象来执行此操作,因为必须使用默认构造函数创建该对象,并通过反射设置值。
不过,您可以使用 Hibernate 自定义类型。阅读Hibernate 参考文档的这一部分,其中有一个示例
Money
类型,它是使用带参数的构造函数实例化的,因此可以是不可变的。You won't be able to do that using standard JPA annotations and an embeddable object, because the object will have to be created using a default constructor, and the value set via reflection.
You could however use a Hibernate custom type. Read this part of the Hibernate reference documentation, where there is an example
Money
type, which is instantiated using a constructor with arguments, and could thus be immutable.