Using Annotations beta 8 and Hibernate 3.1.1.
I have an object, CreditCard in my case. It has contact information, which has an address.
In CreditCard.class:
Code:
@NotNull
@Valid
@Embedded
public SimpleContact getContact() {
return contact;
}
Code:
@MappedSuperclass
@Embeddable
public class SimpleContact implements Serializable {
...
@NotNull
@Length(min = 1, max = MAX_FIRST_NAME)
@Column(name = "fname")
public String getFirstname() {
return fname;
}
@Length(min = 1, max = MAX_MIDDLE_NAME)
@Column(name = "mi")
public String getMi() {
return mi;
}
@Valid
@Embedded
public Address getAddress() {
return address;
}
...
}
Code:
@Embeddable
public class Address {
protected static final int MAX_ADDRESS_LINE1 = 50;
protected static final int MAX_ADDRESS_LINE2 = 50;
...
@NotNull
@Length(min = 1, max = MAX_ADDRESS_LINE1)
@Column(name = "addr1")
public String getAddress1() {
return addr1;
}
@Length(min = 1, max = MAX_ADDRESS_LINE2)
@Column(name = "addr2")
public String getAddress2() {
return addr2;
}
...
}
When I call validator.getInvalidValues(creditCard); it works well. It returns errors when I do not include a first name, or address1. When I do not include mi or address2, the validator does not report an error.
The problem is when the dao is reached and saveOrUpdate(creditCard); is called, I get the stack trace:
Code:
org.hibernate.PropertyValueException: not-null property references a null
or transient value: com.viz.web.model.billing.CreditCard.contact.mi
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:84)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:265)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:167)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:114)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:98)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:529)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:521)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:517)
at org.springframework.orm.hibernate3.HibernateTemplate$18.doInHibernate(HibernateTemplate.java:690)
at org.springframework.orm.hibernate3.HibernateTemplate.execute(HibernateTemplate.java:365)
at org.springframework.orm.hibernate3.HibernateTemplate.saveOrUpdate(HibernateTemplate.java:687)
at com.viz.web.persistence.hibernate.BaseDaoHibernate.save(BaseDaoHibernate.java:115)
at com.viz.web.service.implementation.LookupServiceImpl.save(LookupServiceImpl.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:335)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
at $Proxy36.save(Unknown Source)
at com.viz.web.service.implementation.CustomerServiceImpl.updateCreditCard(CustomerServiceImpl.java:117)
at com.viz.web.controller.springmvc.members.account.CreditCardFormController.onSubmit(CreditCardFormController.java:120)
at org.springframework.web.servlet.mvc.SimpleFormController.processFormSubmission(SimpleFormController.java:258)
at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:259)
at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:139)
at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:44)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:717)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:658)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:392)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:357)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:154)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:92)
at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:106)
at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:229)
at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:259)
at com.caucho.server.port.TcpConnection.run(TcpConnection.java:386)
at com.caucho.util.ThreadPool.runTasks(ThreadPool.java:490)
at com.caucho.util.ThreadPool.run(ThreadPool.java:423)
at java.lang.Thread.run(Thread.java:613)
It seems that the validation logic used by the persistence method is not exactly the same as that used by the classValidator.