Nested Flush during save leads to 'null id in entry' exception

Description

If somehow a flush happens while an object is being saved, following exception is thrown:

net.sf.hibernate.AssertionFailure: null id in entry (don't flush the Session after an exception occurs)
at net.sf.hibernate.impl.SessionImpl.checkId(SessionImpl.java:2605)
at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2429)
at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2422)
at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2224)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2203)
at com.alcatel.util.property.HibernatePropertyStore.getProperty(HibernatePropertyStore.java:34)
at com.alcatel.util.property.ReflectionPropertyGroup.loadProperties(ReflectionPropertyGroup.java:74)
at com.alcatel.util.property.PropertyManager.loadPropertyGroup(PropertyManager.java:79)
at com.alcatel.util.property.PropertyManager.getPropertyGroup(PropertyManager.java:73)
at com.alcatel.util.email.EmailAddress.setEmailAddress(EmailAddress.java:56)
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:324)
at net.sf.hibernate.property.BasicPropertyAccessor$BasicSetter.set(BasicPropertyAccessor.java:38)
at net.sf.hibernate.type.ComponentType.setPropertyValues(ComponentType.java:230)
at net.sf.hibernate.type.ComponentType.deepCopy(ComponentType.java:270)
at net.sf.hibernate.type.TypeFactory.deepCopy(TypeFactory.java:212)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:900)
at net.sf.hibernate.impl.SessionImpl.doSave(SessionImpl.java:839)
at net.sf.hibernate.impl.SessionImpl.saveWithGeneratedIdentifier(SessionImpl.java:757)
at net.sf.hibernate.impl.SessionImpl.save(SessionImpl.java:720)

In our case, a flush was executed during a save because the saved object contained a component (EmailAddress) that has some intelligence in it's setter method. The setter checks the email against a pattern that is stored in the DB. When retrieving the
pattern (using the same (thread local) session), hibernate issues a flush, leading to the exception.
This is just one example, but i guess there will be other ways of (unintentionally) flushing during a save.

Currently, we worked around the problem by explicitly setting the session flushmode to NEVER, but thats not an ideal solution.

Possible solutions:

  • Fix the ComponentType to not call the setter when saving. Does not make to much sense anyway.

  • SessionImpl#flushEntities should not do anything in case the status is SAVING.

For completeness, the EmailAddress component:

public class EmailAddress implements Serializable {

private InternetAddress m_address;
private String m_emailAddress;

public EmailAddress() {
}

public EmailAddress(String emailAddress) throws MalformedEmailException {
setEmailAddress(emailAddress);
}

public String toString() {
return m_emailAddress;
}

/**

  • @hibernate.property

  • column="EMAIL_ADDRESS"
    */
    public String getEmailAddress() {
    return m_emailAddress;
    }

public Address getAddress() {
return m_address;
}

public void setEmailAddress(String stringValue) throws MalformedEmailException {
MailPropertyGroup mailPropertyGroup = (MailPropertyGroup) PropertyManager.getInstance().getPropertyGroup(MailPropertyGroup.GROUP_NAME);
//This leads to the exception above...
Pattern emailPattern = Pattern.compile(mailPropertyGroup.getEmailRegex());
Matcher matcher = emailPattern.matcher(stringValue);
if (!matcher.matches()) {
throw new MalformedEmailException(stringValue);
}
try {
m_address = new InternetAddress(stringValue); //this check alone is not good enough
} catch (AddressException ex) {
throw new MalformedEmailException(stringValue, ex);
}
m_emailAddress = stringValue;
}

Environment

2.1.2 Msql 4.0.17

Status

Assignee

Unassigned

Reporter

Koen Janssens

Labels

None

Worked in

None

Feedback Requested

None

Feedback Requested By

None

backPortable

None

Community Help Wanted

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

backportReEvaluate

None

Components

Affects versions

Priority

Major
Configure