I just finished upgrading from Hibernate 3.6 to 4.1.3 Final, and at first everything seemed fine. However, one of my colleagues recently tested this, and in one scenario, it gets NullPointer, which is thrown from Hibernate (and this exception was not thrown before we updated it for the same database). This is an incredibly strange scenario. We have an object called BlogPost that looks like below, and it extends some mapped superclasses (which I also included):
@Entity
@Table(name = "blog_post")
public class BlogPost extends CommunityModelObject implements HasFeedPost {
@Lob
private String title;
@Lob
private String content;
@Enumerated
@Column(nullable = false)
private CBlogPost.Status status = CBlogPost.Status.UNPUBLISHED;
@OneToOne
@JoinColumn(name = "feed_post_id")
private FeedPost feedPost;
@ManyToOne
@JoinColumn(name = "posted_by_employee_id")
private Employee postedBy;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public CBlogPost.Status getStatus() {
return status;
}
public void setStatus(CBlogPost.Status status) {
this.status = status;
}
@Override
public FeedPost getFeedPost() {
return feedPost;
}
@Override
public void setFeedPost(FeedPost feedPost) {
this.feedPost = feedPost;
}
public Employee getPostedBy() {
return postedBy;
}
public void setPostedBy(Employee postedBy) {
this.postedBy = postedBy;
}
}
@Filter(name = "tenantFilter", condition = "(tenant_id = :tenantId or tenant_id is null)")
@MappedSuperclass
public abstract class CommunityModelObject extends ModelObject {
@IndexedEmbedded(prefix = "tenant", indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
@ManyToOne
@JoinColumn(name = "tenant_id")
protected Tenant tenant;
public Tenant getTenant() {
return tenant;
}
public void setTenant(Tenant tenant) {
this.tenant = tenant;
}
public boolean isCommunityObject() {
return tenant == null;
}
}
@MappedSuperclass
public abstract class ModelObject extends BaseModelObject {
@Id
@GeneratedValue
private Long id;
@Override
public long getId() {
return (id == null ? 0 : id);
}
public void setId(long id) {
this.id = (id == 0 ? null : id);
}
}
@MappedSuperclass
public abstract class BaseModelObject implements java.io.Serializable {
@Transient
private boolean doNotAutoUpdateDateUpdated = false;
@Version
protected int version;
@Column(name = "date_created")
protected Date dateCreated;
@Column(name = "date_updated")
protected Date dateUpdated;
public abstract long getId();
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Date getDateCreated() {
return dateCreated;
}
public Date getDateUpdated() {
return dateUpdated;
}
public void setDateUpdated(Date dateUpdated) {
doNotAutoUpdateDateUpdated = true;
this.dateUpdated = dateUpdated;
}
public void touch() {
dateUpdated = null;
}
@PrePersist
protected void onCreate() {
dateCreated = new Date();
}
@PreUpdate
protected void onUpdate() {
if (!doNotAutoUpdateDateUpdated) {
dateUpdated = new Date();
}
}
@Override
public boolean equals(Object obj) {
long id = getId();
if (id == 0) {
return this == obj;
}
return obj != null &&
obj instanceof BaseModelObject &&
Hibernate.getClass(this) == Hibernate.getClass(obj) &&
getId() == ((BaseModelObject)obj).getId();
}
@Override
public int hashCode() {
Long id = getId();
return id == 0 ? super.hashCode() : id.intValue();
}
@Override
public String toString() {
return getClass().getSimpleName() + "-" + getId();
}
}
, BlogPost . , , , , , :
select b from BlogPost b
java.lang.NullPointerException
at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:240)
at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1153)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1208)
at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)
, , , BlogPost BlogPost java.io.Serializable, . , , Hibernate, CommunityModelObject.
, ? , Hibernate, . , , Hibernate Search, .
, - MySQL , BIT:
public class MySQL5InnoDBDialectExt extends MySQL5InnoDBDialect {
private static final String BIT_STRING = "bit";
public MySQL5InnoDBDialectExt() {
super();
registerColumnType(Types.BOOLEAN, BIT_STRING);
}
}
,
Brent