-
Notifications
You must be signed in to change notification settings - Fork 394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WICKET-6823: Add a container to AbstractTransformerBehavior to support multiple instances per component. #457
base: wicket-8.x
Are you sure you want to change the base?
Changes from 1 commit
b69dee6
20ea1fc
6116b98
7e2a24a
f12ad02
785decc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,11 @@ | |
*/ | ||
package org.apache.wicket.markup.transformer; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Objects; | ||
|
||
import org.apache.wicket.Component; | ||
import org.apache.wicket.Page; | ||
import org.apache.wicket.WicketRuntimeException; | ||
|
@@ -26,17 +31,114 @@ | |
import org.apache.wicket.request.http.WebResponse; | ||
|
||
/** | ||
* A {@link Behavior} which can be added to any component. It allows to post-process (transform) the | ||
* A {@link Behavior} which can be added to any component, allowing to post-process (transform) the | ||
* markup generated by the component. | ||
* | ||
* <p> | ||
* There's one important limitation with the current implementation: Multiple different instances of | ||
* this behavior CAN NOT be assigned to the same component! If one whiches to do so, the contained | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* container needs to be used to wrap existing behaviors and that container needs to be added to the | ||
* component instead. The current implementation of works with temporary responses, but does not | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* support nesting itself properly, which results in missing rendered output and most likely broken | ||
* HTML documents in the end. | ||
* </p> | ||
* @see org.apache.wicket.markup.transformer.AbstractOutputTransformerContainer | ||
* | ||
* @see <a href="https://issues.apache.org/jira/projects/WICKET/issues/WICKET-6823">JIRA issue</a> | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* @author Juergen Donnerstag | ||
*/ | ||
public abstract class AbstractTransformerBehavior extends Behavior implements ITransformer | ||
{ | ||
private static final long serialVersionUID = 1L; | ||
|
||
/** | ||
* Container to apply multiple {@link AbstractTransformerBehavior} to some component. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This javadoc should really be a comment in the PR, not Javadoc. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As someone who ran into that problem, I prefer having such details in the file to get a basic understanding of problems like these without looking at source history, JIRA etc. I regularly miss such details from Wicket's docs and rephrased things to not sound like a commit message too much anymore. |
||
* <p> | ||
* This container is by design NOT about multiple arbitrary transformations, but really only for the | ||
* one use case supporting multiple instances of {@link AbstractTransformerBehavior} on one and the | ||
* same component. The current implementation of that works with temporary responses, but doesn't | ||
* support nesting itself properly in case multiple behaviors assigned to the same component, which | ||
* results in missing rendered output and most likely entirely broken HTML documents in the end. | ||
* </p> | ||
* <p> | ||
* The easiest workaround for that problem is simply introducing this container which users need to | ||
* use in those cases: An instance needs to be created with all transformers of interest in the | ||
* order they should be applied and the container takes care of doing so. Because the container is | ||
* an {@link AbstractTransformerBehavior} itself, things simply work like with individual behaviors, | ||
* while response handling is only managed by the container. So when used with this container, the | ||
* callbacks of the maintained instances like {@link AbstractTransformerBehavior#afterRender(Component)} | ||
* etc., are NOT used anymore! OTOH, the individual behaviors stay useful without the container as | ||
* well. | ||
* </p> | ||
* @see <a href="https://issues.apache.org/jira/projects/WICKET/issues/WICKET-6823">JIRA issue</a> | ||
*/ | ||
public static class Multi extends AbstractTransformerBehavior | ||
{ | ||
private static final long serialVersionUID = 1L; | ||
|
||
/** | ||
* All transformers which need to be applied in the order they need to be applied. | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
*/ | ||
private final List<AbstractTransformerBehavior> transes; | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/** | ||
* CTOR simply storing the given transformers. | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* | ||
* @param transes, which must not be {@code null} or empty, as neither make sense here. | ||
*/ | ||
private Multi(List<AbstractTransformerBehavior> transes) | ||
{ | ||
if ((transes == null) || transes.isEmpty()) | ||
{ | ||
throw new IllegalArgumentException("No transformers given."); | ||
} | ||
|
||
this.transes = transes; | ||
} | ||
|
||
@Override | ||
public CharSequence transform(Component component, CharSequence output) throws Exception | ||
{ | ||
CharSequence retVal = output; | ||
for (AbstractTransformerBehavior trans : this.transes) | ||
{ | ||
retVal = trans.transform(component, retVal); | ||
} | ||
|
||
return retVal; | ||
} | ||
|
||
/** | ||
* Create a new container with the given transformers and with keeping their order. | ||
* <p> | ||
* This factory expects multiple individual transformers already, because creating a container | ||
* with less doesn't make too much sense and users should reconsider then if this container is | ||
* of use at all. In most cases users do have individual transformers to apply only anyway and | ||
* don't need to provide a collection themself this way. OTOH, a collection could be empty or | ||
* contain only one element would then defeat the purpose of this container again. | ||
* </p> | ||
* @param first First transformer to apply. | ||
* @param second Second transformer to apply. | ||
* @param moreIf All other transformers to apply, if at all, in given order. | ||
* @return A container with multiple transformers being applied. | ||
*/ | ||
public static Multi newFor( AbstractTransformerBehavior first, | ||
ams-tschoening marked this conversation as resolved.
Show resolved
Hide resolved
|
||
AbstractTransformerBehavior second, | ||
AbstractTransformerBehavior... moreIf) | ||
{ | ||
List<AbstractTransformerBehavior> transes = new ArrayList<>(); | ||
|
||
transes.add(Objects.requireNonNull(first, "No first transformer given.")); | ||
transes.add(Objects.requireNonNull(second, "No second transformer given.")); | ||
|
||
if ((moreIf != null) && (moreIf.length > 0)) | ||
{ | ||
transes.addAll(Arrays.asList(moreIf)); | ||
} | ||
|
||
return new Multi(transes); | ||
} | ||
} | ||
|
||
/** | ||
* The request cycle's response before the transformation. | ||
*/ | ||
|
@@ -45,10 +147,10 @@ public abstract class AbstractTransformerBehavior extends Behavior implements IT | |
/** | ||
* Create a new response object which is used to store the markup generated by the child | ||
* objects. | ||
* | ||
* | ||
* @param originalResponse | ||
* the original web response or {@code null} if it isn't a {@link WebResponse} | ||
* | ||
* | ||
* @return Response object. Must not be null | ||
*/ | ||
protected BufferedWebResponse newResponse(final WebResponse originalResponse) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This Javadoc is obsolete with the improvement below, no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree,
AbstractTransformerBehavior
itself keeps the limitation and especially existing users should be made aware. The container is only one possible workaround/solution, a different implementation ofAbstractTransformerBehavior
itself would be another one. With that the sentence could be removed, but with the container only the sentence still applies.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can just say "If you need to apply several transformations on the same component then use {@linkplain AbstractTransformerBehavior.Multi}".
I see no need to write 20 lines as Javadoc explaining history.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those 20 lines of history are exactly what I regularly miss when running into trouble with Wicket, because without them there's no basic understanding of why things are the way they are. When running into this problem, I needed to look at the entire GIT-history just to find no reason for the current implementation, no clue on how things were supposed to work, for a workaround fitting the existing design etc.
The docs often lack important context from my experience, so I'm trying to add one here.