Hi everyone,
I asked a question about a week ago about using custom wrappers for returned objects, and I got a few answers. However, I also found this topic on Stackoverflow: Correct way to wrap persistent set in hibernate, which is basically what I want to do. However, after trying out this method I get the following error:
org.hibernate.MappingException: Cannot instantiate custom type: org.autofetch.hibernate.AutofetchSetType
Which makes sense, since AutofetchSetType does not have an empty constructor for initialization. This is the two wrapper classes that I’m using:
public class AutofetchSetType extends SetType implements UserCollectionType {
/**
*
*/
private static final long serialVersionUID = 1L;
public AutofetchSetType(TypeScope typeScope, String role, String propertyRef) {
super(typeScope, role, propertyRef);
}
@Override
public PersistentCollection instantiate(SessionImplementor session,
CollectionPersister persister, Serializable key) {
return new AutofetchSet(session);
}
@Override
public PersistentCollection wrap(SessionImplementor session,
Object collection) {
return new AutofetchSet(session, (java.util.Set) collection);
}
@Override
public Iterator getElementsIterator(Object collection) {
return ((PersistentSet)collection).iterator();
}
@Override
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister)
throws HibernateException {
return new AutofetchSet(session);
}
@Override
public boolean contains(Object collection, Object entity) {
return ((PersistentSet) collection).contains(entity);
}
@Override
public Object replaceElements(Object original, Object target, CollectionPersister persister, Object owner,
Map copyCache, SessionImplementor session) throws HibernateException {
((PersistentSet) target).clear();
((PersistentSet) target).addAll((Collection<?>) original);
return target;
}
}
public class AutofetchSet extends PersistentSet implements Trackable {
private CollectionTracker collectionTracker = new CollectionTracker();
public AutofetchSet() {
super();
}
public AutofetchSet(SessionImplementor si, Set s) {
super(si, s);
}
public AutofetchSet(SessionImplementor si) {
super(si);
}
public void addTracker(Statistics tracker) {
collectionTracker.addTracker(tracker);
}
public void addTrackers(Set<Statistics> trackers) {
collectionTracker.addTrackers(trackers);
}
public boolean disableTracking() {
boolean oldValue = collectionTracker.isTracking();
collectionTracker.setTracking(false);
return oldValue;
}
public boolean enableTracking() {
boolean oldValue = collectionTracker.isTracking();
collectionTracker.setTracking(true);
return oldValue;
}
public void removeTracker(Statistics stats) {
collectionTracker.removeTracker(stats);
}
private void accessed() {
if (wasInitialized()) {
collectionTracker.trackAccess(set);
}
}
/**
* @see java.util.Set#size()
*/
@Override
public int size() {
int ret = super.size();
if (wasInitialized()) {
accessed();
}
return ret;
}
/**
* @see java.util.Set#isEmpty()
*/
@Override
public boolean isEmpty() {
boolean ret = super.isEmpty();
if (wasInitialized()) {
accessed();
}
return ret;
}
/**
* @see java.util.Set#contains(Object)
*/
@Override
public boolean contains(Object object) {
boolean ret = super.contains(object);
if (wasInitialized()) {
accessed();
}
return ret;
}
/**
* @see java.util.Set#iterator()
*/
@Override
public Iterator iterator() {
Iterator iter = super.iterator();
if (wasInitialized()) {
accessed();
}
return iter;
}
/**
* @see java.util.Set#toArray()
*/
@Override
public Object[] toArray() {
Object[] arr = super.toArray();
if (wasInitialized()) {
accessed();
}
return arr;
}
/**
* @see java.util.Set#toArray(Object[])
*/
@Override
public Object[] toArray(Object[] array) {
Object[] arr = super.toArray(array);
if (wasInitialized()) {
accessed();
}
return arr;
}
/**
* @see java.util.Set#add(Object)
*/
@Override
public boolean add(Object value) {
Boolean exists = isOperationQueueEnabled()
? readElementExistence(value) : null;
if (exists == null) {
initialize(true);
accessed();
if (set.add(value)) {
dirty();
return true;
} else {
return false;
}
} else {
return super.add(value);
}
}
/**
* @see java.util.Set#remove(Object)
*/
@Override
public boolean remove(Object value) {
boolean ret = super.remove(value);
if (wasInitialized()) {
accessed();
}
return ret;
}
/**
* @see java.util.Set#containsAll(Collection)
*/
@Override
public boolean containsAll(Collection coll) {
boolean ret = super.containsAll(coll);
if (wasInitialized()) {
accessed();
}
return ret;
}
/**
* @see java.util.Set#addAll(Collection)
*/
@Override
public boolean addAll(Collection coll) {
if (coll.size() > 0) {
initialize(true);
accessed();
if (set.addAll(coll)) {
dirty();
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* @see java.util.Set#retainAll(Collection)
*/
@Override
public boolean retainAll(Collection coll) {
boolean val = super.retainAll(coll);
if (wasInitialized()) {
accessed();
}
return val;
}
/**
* @see java.util.Set#removeAll(Collection)
*/
@Override
public boolean removeAll(Collection coll) {
boolean val = super.removeAll(coll);
if (wasInitialized()) {
accessed();
}
return val;
}
@Override
public void clear() {
super.clear();
if (wasInitialized()) {
accessed();
}
}
@Override
public String toString() {
//if (needLoading) return "asleep";
String ret = super.toString();
if (wasInitialized()) {
accessed();
}
return ret;
}
@Override
public boolean equals(Object other) {
boolean ret = super.equals(other);
if (wasInitialized()) {
accessed();
}
return ret;
}
@Override
public int hashCode() {
int ret = super.hashCode();
if (wasInitialized()) {
accessed();
}
return ret;
}
public boolean isAccessed() {
return collectionTracker.isAccessed();
}
}
This is how I map my entities:
@Entity
@Tuplizer(impl = AutofetchTuplizer.class)
public class Employee {
@Id
@Column(name = "employee_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long m_id;
@Column(name = "name")
private String m_name;
@JoinColumn(name = "supervisor_id")
@ManyToOne(cascade = {CascadeType.ALL})
private Employee m_supervisor;
@CollectionType(type="org.autofetch.hibernate.AutofetchSetType")
@JoinColumn(name = "supervisor_id")
@OneToMany(cascade = {CascadeType.ALL})
private Set<Employee> m_subordinates;
@Embedded
private Address m_address;
@JoinColumn(name = "mentor_id")
@ManyToOne(cascade = {CascadeType.ALL})
private Employee m_mentor;
@Type(type="org.autofetch.hibernate.AutofetchSetType")
@CollectionType(type="org.autofetch.hibernate.AutofetchSetType")
@ManyToMany(cascade = {CascadeType.ALL})
@JoinTable(name = "friends", joinColumns = {@JoinColumn(name = "friend_id")}, inverseJoinColumns = {@JoinColumn(name = "befriended_id")})
private Set<Employee> m_friends;
So it’s clear why I’m getting the error, hibernate does not find an empty constructor for this type, but I can’t find any documentation how the integration of my wrapper is supposed to be done. Am I using the annotation for the type incorrectly? Any ideas?