Hi!
I have been struggling with a bug related to composite components and dynamic tree modification using either c:if or ui:include tags. I submitted the initial issue to JIRA almost a year ago, but it was closed as "Works as designed". Probably my description and reproducer were not explicit enough. There have been two other reports about the same bug after that, and the first of them had the same fate - "Works as designed". The last one is still open, though. In this case, being open is better than being closed as "Works as designed"!
Anyway, here's a brand new reproducer I created this week:
https://github.com/tuner/mojarra-dynamic-include-reproducer/
If new instances of a specific composite component are added to the component tree between restore and render phases, the addition sometimes works and sometimes doesn't. This depends on the order the components are added. If the component is added to the end, everything works just as expected. However, if the component is added to the middle or to the beginning, something goes wrong and the contents of a composite component get duplicated. The duplication doesn't happen in the component that was just added, but in the next component in the component tree. If the composite component contains components that have an explicit id, an exception is thrown: Component ID x:x:x has already been found in the view. Otherwise, the contents just get duplicated.
But in the tree, what does the order of the components actually mean? It means the order in which the components are encountered when the tree is traversed in-order. Adding "wrapper" components or defining explicit ids for the composite components or their containers seem to have no effect at all.
This behavior makes me think that the components are given an index number in the order they are encountered. And when something is added or removed in the middle, the indexing goes wrong and an existing component that we were looking for can't be found. A new one is created instead and the duplication occurs.
Component tree creation seems to be so complicated that I have major difficulties trying to understand how it works. By tracing component creation with a debugger, I might have found some clues to this issue, though.
In ComponentTagHandlerDelegateImpl there's:
String id = getMarkId(ctx, parent);
UIComponent c = findChild(ctx, parent, id);
MarkId seems to be some sort of build-time identifier for components (or tags?). Depending on whether something was found or not, a component is reused or a new one is created.
This is an example of a mark id: 739245247_2_40b31929_2. The first number is a hashcode for the facelet hierarchy, like /web/index.xhtml,/web/component.xhtml. The second number is some sort of index number which is incremented every time a specific facelet hierarchy is encountered. The third one is a tag id, for which I have absolutely no idea where it comes from. And the last number is an index number for the tag id. It is incremented in the same manner as the facelet hierarchy number.
Maybe mark id is not related to this issue at all, but to me, this indexing logic looks compatible with the hypothesis I came up while playing with the reproducer I created.
I figured out the exact Mojarra versions where the bug initially appeared, and I'm quite certain that it's related to the fix of issue JAVASERVERFACES-2494. However, mark id was introduced prior to this fix, but maybe it wasn't used for component lookup in a critical place.
I think I'm not able to fix this myself - this part of Mojarra is just too complex for me to grasp in a reasonable time. Hopefully, my findings have some use solving the issue.
Thanks for reading!
Regards,
Kari Lavikka