Custom datastructures (wrappers) are not being used (4.3.10)


#1

Hi everyone,

In my migration project (4.3.10 still) I’m using custom wrappers for some of the datastructures in Hibernate, such as Bag, Set etc. This is done in order to track the objects (implements Trackable). My problem is that they are not being used while running the tests, and it fails due to this. (The tests uses the normal persistentSet etc instead)

From what I’ve understood, the binding to these objects is done in the HbmBinder-class. I’ve modified this to wrap the objects to make them have the extra functionality. However, the HbmBinder.bindRoot-method is never being called due to the extendsQueue is null:

private int processExtendsQueue() {
        LOG.debug("Processing extends queue");
        int added = 0;
        ExtendsQueueEntry extendsQueueEntry = findPossibleExtends(); // trying to get an entry from the queue
        while (extendsQueueEntry != null) {
            metadataSourceQueue.processHbmXml(extendsQueueEntry.getMetadataXml(), extendsQueueEntry.getEntityNames());
            extendsQueueEntry = findPossibleExtends();
        }

        if (extendsQueue.size() > 0) {
            Iterator iterator = extendsQueue.keySet().iterator();
            StringBuilder buf = new StringBuilder("Following super classes referenced in extends not found: ");
            while (iterator.hasNext()) {
                final ExtendsQueueEntry entry = (ExtendsQueueEntry) iterator.next();
                buf.append(entry.getExplicitName());
                if (entry.getMappingPackage() != null) {
                    buf.append("[").append(entry.getMappingPackage()).append("]");
                }
                if (iterator.hasNext()) {
                    buf.append(",");
                }
            }
            throw new MappingException(buf.toString());
        }

        return added;
    }
    @Override
    protected ExtendsQueueEntry findPossibleExtends() {
        Iterator<ExtendsQueueEntry> itr = extendsQueue.keySet().iterator();
        while (itr.hasNext()) {
            final ExtendsQueueEntry entry = itr.next();
            boolean found = getClassMapping(entry.getExplicitName()) != null || getClassMapping(
                    AutofetchHbmBinder.getClassName(entry.getExplicitName(), entry.getMappingPackage())) != null;
            if (found) {
                itr.remove();
                return entry;
            }
        }
        return null;
    }

The only place where something is added this extendsQueue is in the HbmBinder itself, which means that the extendsQueue initially is empty, it will never have any content:

 public static void bindRoot(XmlDocument metadataXml, Mappings mappings, java.util.Map inheritedMetas,
                                java.util.Set<String> entityNames) throws MappingException {

        final Document doc = metadataXml.getDocumentTree();
        final Element hibernateMappingElement = doc.getRootElement();

        java.util.List<String> names = AutofetchHbmBinder.getExtendsNeeded(metadataXml, mappings);
        if (!names.isEmpty()) {
            // classes mentioned in extends not available - so put it in queue
            Attribute packageAttribute = hibernateMappingElement.attribute("package");
            String packageName = packageAttribute == null ? null : packageAttribute.getValue();
            for (String name : names) {
                mappings.addToExtendsQueue(new ExtendsQueueEntry(name, packageName, metadataXml, entityNames));
            }
            return;
        }
...

Am I misunderstanding something here? Any ideas what I should look for in order to make sure that my own custom classes gets used?

Update:
I realize now that it could be due to that in the original version, hbm was the intended way to supply the mapping, but now I instead use annotations. Could this be the reason why the creation of the wrappers does not work? If so, what class in hibernate nowadays handles the creation of the different datastructures, in the same manner as the HbmBinder handles it in the case of hbm-mapping?


#2

Unfortunately, the 4.3 is way too different than 5.2 or 5.3 which we are working on so I won’t be able to help you with it.


#3

Well, in the current version, how do you add custom collections? Is it via the @CollectionType annotation?


#4

I don’t think I’ve ever needed to customize the Hibernate internal collection Proxies. Why would you want to do that?


#5

To make sure that the used collection type is my own custom type. My custom types extends the normal persistentSet etc so that they are trackable. I don’t see how I can make hibernate use my extended classes if this is not the way to do it.


#6

What do you want to “track” exactly ?

Other techniques exist that will not interfere as much with the internal of the ORM and thus probably may not raise the risks like what you are trying to do,
define an hibernate.ejb.interceptor or use AspectJ as examples.


#7

If your types are actual wrappers, could you apply/unapply them in the setters and getters and make Hibernate use those?


#8

I differentiate the normal Hibernate collection types from my special “trackable” collections by making my collections implement trackable. During runtime, there will be a check when loading entities if the collection is a trackable or not, and if it is it will be used in the building of the entitygraph, which can be used to automate the prefetching based on a heuristic (used/fetched percentage).


#9

How do you mean? Where would I apply/unapply the custom types? Still a bit of a Hibernate beginner so I would appreciate a little bit of a detailed explanation. :slightly_smiling_face:


#10

Something like this

class MyEntity {

     MyWrapper someCollection = new MyWrapper(new ArrayList());

    public void setSomeCollection(List aList){
        someCollection = new MyWrapper(aList);
    }

   public List getSomeCollection() {
       return someCollection.getWrapped() // returns the wrapped collection
   }
}

#11

Thanks for the suggestion. This is basically how my wrappers look like, the problem is that I can’t get hibernate to actually use the wrappers.