protected void assignInstanceValuesFromResult( T instance, List<PropertyConfig> instancePropertyConfigs, DatabaseResults results, Map<String, Integer> colPosMap, Object id, Boolean foreignCollections, ObjectCache objectCache) throws SQLException { for (PropertyConfig propertyConfig : instancePropertyConfigs) { if (propertyConfig.isForeignCollection()) { foreignCollections = true; } else { Object val = propertyConfig.resultToJava(results, colPosMap); /* * This is pretty subtle. We introduced multiple foreign fields to the same type which use the {@link * ForeignCollectionField} foreignColumnName field. The bug that was created was that all the fields * were then set with the parent class. Only the fields that have a matching id value should be set to * the parent. We had to add the val.equals logic. */ if (val != null && parent != null && propertyConfig.getField().getType() == parent.getClass() && val.equals(parentId)) { propertyConfig.assignField(instance, parent, true, objectCache); } else { propertyConfig.assignField(instance, val, false, objectCache); } if (propertyConfig == idField) { id = val; } } } }
public T mapRow(DatabaseResults results) throws SQLException { Map<String, Integer> colPosMap; if (columnPositions == null) { colPosMap = new HashMap<String, Integer>(); } else { colPosMap = columnPositions; } ObjectCache objectCache = results.getObjectCache(); Object id = null; if (objectCache != null) { id = idField.resultToJava(results, colPosMap); T cachedInstance = objectCache.get(entityConfig, id); if (cachedInstance != null) { // if we have a cached instance for this id then return it return cachedInstance; } } // create our instance List<PropertyConfig> instancePropertyConfigs = new ArrayList<>(); T instance = createInstanceForResults( entityConfig, results, colPosMap, instancePropertyConfigs, resultsPropertyConfigs); if (objectCache != null && id != null) { // why not adding instance already here to cache? Avoids multiple retrievals on (deep) // recursive dependencies on its fields objectCache.put( (Class<T>) instance.getClass(), id, instance); // don't use clazz variable here as for tables with inheritance this might be // wrong (it might only be the parent class) } // populate its fields Boolean foreignCollections = false; for (PropertyConfig propertyConfig : instancePropertyConfigs) { if (propertyConfig.isForeignCollection()) { foreignCollections = true; } else { Object val = propertyConfig.resultToJava(results, colPosMap); /* * This is pretty subtle. We introduced multiple foreign fields to the same type which use the {@link * ForeignCollectionField} foreignColumnName field. The bug that was created was that all the fields * were then set with the parent class. Only the fields that have a matching id value should be set to * the parent. We had to add the val.equals logic. */ if (val != null && parent != null && propertyConfig.getType() == parent.getClass() && val.equals(parentId)) { propertyConfig.assignField(instance, parent, true, objectCache); } else { propertyConfig.assignField(instance, val, false, objectCache); } if (propertyConfig == idField) { id = val; } } } // if we have a cache and we have an id then add it to the cache // if (objectCache != null && id != null) { // for ManyToMany collections it is of great // importance that instance will be cached already here, before ForeignCollections will be built // objectCache.put(clazz, id, instance); // } if (foreignCollections) { // go back and initialize any foreign collections for (PropertyConfig propertyConfig : instancePropertyConfigs) { if (propertyConfig.isForeignCollection()) { Collection collection = propertyConfig.buildForeignCollection( instance, id); // cda: implement against interfaces, not implementations if (collection != null) { propertyConfig.assignField(instance, collection, false, objectCache); } } } } if (columnPositions == null) { columnPositions = colPosMap; } entityConfig.invokePostLoadLifeCycleMethod(instance); return instance; }