bug #7331
Updated by Andreas Müller almost 4 years ago
In the `RegistrationWorkingSetService.loadWorkingSetByReferenceID(Integer referenceID)` a `RegistrationWorkingSet` is loaded with the following code: ~~~java List<String> REGISTRATION_INIT_STRATEGY = Arrays.asList(new String []{ "blockedBy", // typeDesignation "typeDesignations.typeStatus", "typeDesignations.typifiedNames.typeDesignations", // important !! "typeDesignations.typeSpecimen", "typeDesignations.typeName.$", "typeDesignations.citation", "typeDesignations.citation.authorship.$", // name "name.$", "name.nomenclaturalReference.authorship.$", "name.nomenclaturalReference.inReference", "name.rank", "name.homotypicalGroup.typifiedNames", "name.status.type", "name.typeDesignations", // important !!" // institution "institution", } ); Reference reference = repo.getReferenceService().find(referenceID); Pager<Registration> pager = repo.getRegistrationService().page(Optional.of(reference), null, null, null, REGISTRATION_INIT_STRATEGY); return new RegistrationWorkingSet(makeDTOs(pager.getRecords())); ~~~ This usually works, but with a specific data set the `pager` contains `Registrations` where `authorship` properties of the `nomenclaturalReferences` are not initialized initializes even if the `AdvancedBeanInitializer` apparently is doing the initialization properly (also confirmed by debugging): ~~~ [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - processing /name.nomenclaturalReference [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - invoke initialization on /name.nomenclaturalReference beans of class TaxonName ... [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - bulk load /name.nomenclaturalReference [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - bulk load /name.nomenclaturalReference - DONE [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - processing /name.nomenclaturalReference.authorship [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - invoke initialization on /name.nomenclaturalReference.authorship beans of class Reference ... [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - bulk load /name.nomenclaturalReference.authorship [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - bulk load beans of class TeamOrPersonBase [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - SELECT c FROM TeamOrPersonBase as c WHERE c.id IN (:idSet) [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - initialize bulk loaded beans of class TeamOrPersonBase: [1383] [eu.et.cd.pe.da.in.AdvancedBeanInitializer] - bulk load - DONE ~~~ The actual initialization takes place in `AdvancedBeanInitializer.bulkLoadLazyBeans(BeanInitNode node)`. Here a strange behavior can be observed in these special cases: ~~~java private void bulkLoadLazyBeans(node node) { for (Class<?> clazz : node.getLazyBeans().keySet()){ Set<Serializable> idSet = node.getLazyBeans().get(clazz); String hql = " SELECT c FROM %s as c %s WHERE c.id IN (:idSet) "; hql = String.format(hql, clazz.getSimpleName(), autoInit.leftJoinFetch); // hql = "SELECT c FROM TeamOrPersonBase as c WHERE c.id IN (:idSet)" Query query = genericDao.getHqlQuery(hql); query.setParameterList("idSet", idSet); List<Object> list = query.list(); ~~~ Now the TeamOrPersonBase entities are initialized. **However, checking the `parent` object contained in the `node` object passed as parameer reveals that the 'authorship' proxy in the object graph has not been initialized.** Preloading the reference in the `RegistrationWorkingSetService.loadWorkingSetByReferenceID(Integer referenceID)` method avoids the problem (in the below code only relevant lines are shown) ~~~java Reference reference = repo.getReferenceService().find(referenceID); repo.getReferenceService().load(reference.getUuid()); ~~~ Since this behavior is data dependent, I serialized the fully initialized registrations as loaded in the `RegistrationDaoHibernateImpl.list(Optional<Reference> reference, Collection<RegistrationStatus> includedStatus, Integer limit, Integer start, List<String> propertyPaths)`. attachment:registrations-fully-initialized.ser can be used to restore the original data by de-serializing and persisting the objects to a cdm-database (version 4.15.0-SNAPSHOT) : ~~~java try { FileInputStream fin = new FileInputStream("registrations-fully-initialized.ser"); ObjectInputStream oin = new ObjectInputStream(fin); List<Registration> registrationsDeserialized = (List<Registration>) oin.readObject(); } catch (ClassNotFoundException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } ~~~ **NOTE: Doing the serialization in `RegistrationDaoHibernateImpl.list()` also removed the problem described in here:** ~~~java try { FileOutputStream fout = new FileOutputStream("registrations-before-initialization.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(results); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } defaultBeanInitializer.initializeAll(results, propertyPaths); // initialization is incomplete try { FileOutputStream fout = new FileOutputStream("registrations-after-initialization.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(results); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // fully initialized now! the file registrations-fully-initialized.ser has been created after this ~~~ --- **Additional tasks:** * remove commit:af4969c833 and test carefully!!! **Potentially duplicate tickets:** * #9095 * #9096 ---