I am in the process of defining the mapping of an object via an hbm.xml file because inheritance is not working correctly and is preventing the use of standard annotations.
I have almost managed to do everything, but I am unable to provide the definition for the @EntityListeners.
I have the impression that CallbackDefinition on the PersistentClass is only populated with annotations. I even tried adding it by default, but it doesn’t work for HBM entities.
Basically, I have the impression that for HBM, there is nothing to transmit the listeners, but that seems strange to me. Am I missing something?
You can alter some static variable i.e. static boolean called; in your listener and check that the flag was set in an assertion to verify that a listener was called.
Note that for configuration via XML file, it would be possible to specify default listeners for all entities (which I will test), and it’s not possible to define a specific one for a particular entity.
With hbm.xml it’s not possible, but with pure orm.xml you can define a listener per entity/mapped-superclass. Who knows, maybe it even works in combination with hbm.xml. I haven’t tried though.
I just noticed that the use of <hibernate-mapping> is deprecated (hbm.xml).
It suggests using orm.xml or mapping.xml or enable hibernate.transform_hbm_xml.
Which do you think is better to use?
10:58:33,447|WARN |{}|orm.deprecation|main|HHH90000028: Support for <hibernate-mappings/> is deprecated [INPUT_STREAM : D:\java\workspaces\developpement_dev\efluid\app\target\classes\com\hermes\ref\acteur\businessobject\ActeurInterne.hbm.xml]; migrate to orm.xml or mapping.xml, or enable hibernate.transform_hbm_xml.enabled for on the fly transformation
The best way IMO is to use annotations, but if you must use XML, you should use orm.xml since hbm.xml will probably be removed in ORM 7, which will be released later this year.
hbm.xml is a separate complete definition from the mapping but it will disappear
orm.xml is simply the completion of annotations by text file
In my case, the issue is that I want to avoid keeping an inheritance from a problematic parent class, so I am forced to use hbm.xml.
It’s worth noting that this is temporary, just while we make the necessary changes to the incorrect model. This will resolve the situation for the next 6 to 8 months.
I know that HBM.xml files are going to disappear, but I had adopted this solution to create callbacks on the PersistentClass.
I just migrated it when upgrading to 7.2.5.
I’m a bit surprised to see that they are still present, which—honestly—works in my favor, since it gives us a bit more time to migrate the concepts that are problematic for us.
It also allows me to record it as well.
package com.efluid.hibernate.core.sessionfactory;
import org.hibernate.boot.ResourceStreamLocator;
import org.hibernate.boot.spi.AdditionalMappingContributions;
import org.hibernate.boot.spi.AdditionalMappingContributor;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.jpa.event.internal.CallbackDefinitionResolver;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.ClassDetailsRegistry;
import com.hermes.arc.commun.businessobject.HermesBusinessObject;
/**
* Résout le problème de ne pas pouvoir transmettre de callback (listener) via HBM (fichier xml).
* Voir https://discourse.hibernate.org/t/unable-to-pass-the-listeners-callback-to-hbm/8889/1
* <p>
* Intervient pendant la phase de build des métadonnées, au moment où InFlightMetadataCollector
* est encore vivant — ce qui permet d'appeler resolveLifecycleCallbacks qui en a besoin.
* <p>
* Parcourt toutes les PersistentClass mappant une classe héritant de HermesBusinessObject
* et sans callback, puis les résout comme le ferait @PrePersist / @PostXxx via annotations.
*/
public class EfluidCallbackHbmContributor implements AdditionalMappingContributor {
@Override
public String getContributorName() {
return "EfluidCallbackHbmContributor";
}
@Override
public void contribute(
AdditionalMappingContributions contributions,
InFlightMetadataCollector metadata,
ResourceStreamLocator resourceStreamLocator,
MetadataBuildingContext buildingContext) {
ClassDetailsRegistry registry = metadata.getClassDetailsRegistry();
metadata.getEntityBindings().stream()
.filter(this::isPersistentClassSansCallback)
.forEach(persistentClass -> {
ClassDetails classDetails = registry.getClassDetails(persistentClass.getMappedClass().getName());
CallbackDefinitionResolver.resolveLifecycleCallbacks(classDetails, persistentClass, metadata);
});
}
private boolean isPersistentClassSansCallback(PersistentClass persistentClass) {
return persistentClass.getCallbackDefinitions().isEmpty() && HermesBusinessObject.class.isAssignableFrom(persistentClass.getMappedClass());
}
}