-
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 all commits
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 wishes to do so, the contained | ||
* container needs to be used to wrap existing behaviors and that container needs to be added to the | ||
* component instead. The current implementation works with temporary responses, but doesn't 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 | ||
* | ||
* | ||
* @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 makes use of temporary responses, | ||
* but doesn't support nesting itself properly if multiple behaviors get assigned to the same | ||
* component. That results in missing rendered output and most likely entirely broken HTML. | ||
* </p> | ||
* <p> | ||
* The easiest workaround for that problem is using this container 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. Being an {@link AbstractTransformerBehavior} itself, | ||
* things simply work like with individual behaviors, while response handling is managed by the | ||
* container only. This means that callbacks of the internally maintained instances, like | ||
* {@link AbstractTransformerBehavior#afterRender(Component)} etc., are NOT used anymore! OTOH, | ||
* this way the behaviors stay individually 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 given by the user, which is the | ||
* same order as processed by the container in the end. | ||
*/ | ||
private final List<AbstractTransformerBehavior> transformers; | ||
|
||
/** | ||
* Constructor simply storing the given transformers. | ||
* | ||
* @param transformers, which must not be {@code null} or empty. Wouldn't makes sense here. | ||
*/ | ||
private Multi(List<AbstractTransformerBehavior> transformers) | ||
{ | ||
if ((transformers == null) || transformers.isEmpty()) | ||
{ | ||
throw new IllegalArgumentException("No transformers given."); | ||
} | ||
|
||
this.transformers = transformers; | ||
} | ||
|
||
@Override | ||
public CharSequence transform(Component component, CharSequence output) throws Exception | ||
{ | ||
CharSequence retVal = output; | ||
for (AbstractTransformerBehavior trans : this.transformers) | ||
{ | ||
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, as creating a container | ||
* with less of those 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, contain only one element etc. and 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 of( AbstractTransformerBehavior first, | ||
AbstractTransformerBehavior second, | ||
AbstractTransformerBehavior... moreIf) | ||
{ | ||
List<AbstractTransformerBehavior> transformers = new ArrayList<>(); | ||
|
||
transformers.add(Objects.requireNonNull(first, "No first transformer given.")); | ||
transformers.add(Objects.requireNonNull(second, "No second transformer given.")); | ||
|
||
if ((moreIf != null) && (moreIf.length > 0)) | ||
{ | ||
transformers.addAll(Arrays.asList(moreIf)); | ||
} | ||
|
||
return new Multi(transformers); | ||
} | ||
} | ||
|
||
/** | ||
* 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.