[jira] [Comment Edited] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187338#comment-17187338 ] Sven Meier edited comment on WICKET-6823 at 8/30/20, 9:51 PM: -- Wicket 9.x tests all work fine with this change though. was (Author: svenmeier): Wicket tests all work fine with this change though. > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >Reporter: Thorsten Schöning >Assignee: Sven Meier >Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > > [...] > > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request, content is rendered and > transformed, using the current request AND changing it back to what each > individual transformer believes to be the original request. > {noformat} > @Override > public void afterRender(final Component component) > { > final RequestCycle requestCycle = RequestCycle.get(); > try > { > BufferedWebResponse tempResponse = > (BufferedWebResponse)requestCycle.getResponse(); > if (component instanceof Page && originalResponse instanceof > WebResponse) > { > tempResponse.writeMetaData((WebResponse) > originalResponse); > } > // Transform the data > CharSequence output = transform(component, > tempResponse.getText()); > originalResponse.write(output); > } >
[jira] [Commented] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187338#comment-17187338 ] Sven Meier commented on WICKET-6823: Wicket tests all work fine with this change though. > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >Reporter: Thorsten Schöning >Assignee: Sven Meier >Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > > [...] > > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request, content is rendered and > transformed, using the current request AND changing it back to what each > individual transformer believes to be the original request. > {noformat} > @Override > public void afterRender(final Component component) > { > final RequestCycle requestCycle = RequestCycle.get(); > try > { > BufferedWebResponse tempResponse = > (BufferedWebResponse)requestCycle.getResponse(); > if (component instanceof Page && originalResponse instanceof > WebResponse) > { > tempResponse.writeMetaData((WebResponse) > originalResponse); > } > // Transform the data > CharSequence output = transform(component, > tempResponse.getText()); > originalResponse.write(output); > } > catch (Exception ex) > { > throw new WicketRuntimeException("Error while transforming the > output of
[jira] [Commented] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187335#comment-17187335 ] Sven Meier commented on WICKET-6823: Problem is that #beforeRender() and #afterRender() are *not* invoked 'nested' on the behaviors: * beforeRender is called on FooTrans * beforeRender is called on BarTrans * afterRender is called on FooTrans * afterRender is called on BarTrans To allow multiple transformers the sequence has to be: * beforeRender is called on FooTrans * beforeRender is called on BarTrans * afterRender is called on BarTrans * afterRender is called on FooTrans This can be fixed by reversing the iteration in Component#notifyBehaviorsComponentRendered() {code:java} private void notifyBehaviorsComponentRendered() { // notify the behaviors in *reverse* that component has been rendered for (Behavior behavior : new ReverseListIterator<>(getBehaviors())) { if (isBehaviorAccepted(behavior)) { behavior.afterRender(this); } } }{code} This might break existing applications, so we'll have to decide whether this change is worth it. Personally I never used more than one transformer on a component. > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >Reporter: Thorsten Schöning >Assignee: Sven Meier >Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > > [...] > > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request,
[jira] [Assigned] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Sven Meier reassigned WICKET-6823: -- Assignee: Sven Meier > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >Reporter: Thorsten Schöning >Assignee: Sven Meier >Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > > [...] > > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request, content is rendered and > transformed, using the current request AND changing it back to what each > individual transformer believes to be the original request. > {noformat} > @Override > public void afterRender(final Component component) > { > final RequestCycle requestCycle = RequestCycle.get(); > try > { > BufferedWebResponse tempResponse = > (BufferedWebResponse)requestCycle.getResponse(); > if (component instanceof Page && originalResponse instanceof > WebResponse) > { > tempResponse.writeMetaData((WebResponse) > originalResponse); > } > // Transform the data > CharSequence output = transform(component, > tempResponse.getText()); > originalResponse.write(output); > } > catch (Exception ex) > { > throw new WicketRuntimeException("Error while transforming the > output of component: " + > component, ex); > } >
[jira] [Commented] (WICKET-6824) Use concatenation instead of String.format for frequently called methods
[ https://issues.apache.org/jira/browse/WICKET-6824?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187326#comment-17187326 ] Sven Meier commented on WICKET-6824: Thanks Thomas, your performance analyses are highly appreciated. Sorry that I've already merged your PR, I didn't recognize you when looking at it. > Use concatenation instead of String.format for frequently called methods > > > Key: WICKET-6824 > URL: https://issues.apache.org/jira/browse/WICKET-6824 > Project: Wicket > Issue Type: Improvement > Components: wicket-core >Affects Versions: 9.0.0 >Reporter: Thomas Heigl >Assignee: Thomas Heigl >Priority: Minor > Attachments: image-2020-08-30-20-34-57-261.png, > image-2020-08-30-20-35-04-970.png > > > Two usages of {{String.format}} frequently show up in my production profiler: > !image-2020-08-30-20-34-57-261.png! > !image-2020-08-30-20-35-04-970.png! > Both methods are potentially called dozens or even hundreds of times for > large pages. > {{String.format}} has horrible performance and should mostly be used for > generating error messages and debug information. For a detailed analysis see: > [https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8] > We should replace {{String.format}} with simple concatenation in both > instances. -- This message was sent by Atlassian Jira (v8.3.4#803005)
buildbot failure in on wicket-master-java14
The Buildbot has detected a new failure on builder wicket-master-java14 while building wicket. Full details are available at: https://ci.apache.org/builders/wicket-master-java14/builds/235 Buildbot URL: https://ci.apache.org/ Buildslave for this Build: bb_slave6_ubuntu Build Reason: The SingleBranchScheduler scheduler named 'on-wicket-master-java14-commit' triggered this build Build Source Stamp: [branch master] ad5e81b83b49ba1b58945cb14df1a63fa508f44a Blamelist: Thomas Heigl BUILD FAILED: failed compile Sincerely, -The Buildbot
[jira] [Commented] (WICKET-6824) Use concatenation instead of String.format for frequently called methods
[ https://issues.apache.org/jira/browse/WICKET-6824?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187324#comment-17187324 ] ASF subversion and git services commented on WICKET-6824: - Commit ad5e81b83b49ba1b58945cb14df1a63fa508f44a in wicket's branch refs/heads/master from Thomas Heigl [ https://gitbox.apache.org/repos/asf?p=wicket.git;h=ad5e81b ] WICKET-6824 Replace slow `String.format` with concatenation This closes #449 > Use concatenation instead of String.format for frequently called methods > > > Key: WICKET-6824 > URL: https://issues.apache.org/jira/browse/WICKET-6824 > Project: Wicket > Issue Type: Improvement > Components: wicket-core >Affects Versions: 9.0.0 >Reporter: Thomas Heigl >Assignee: Thomas Heigl >Priority: Minor > Attachments: image-2020-08-30-20-34-57-261.png, > image-2020-08-30-20-35-04-970.png > > > Two usages of {{String.format}} frequently show up in my production profiler: > !image-2020-08-30-20-34-57-261.png! > !image-2020-08-30-20-35-04-970.png! > Both methods are potentially called dozens or even hundreds of times for > large pages. > {{String.format}} has horrible performance and should mostly be used for > generating error messages and debug information. For a detailed analysis see: > [https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8] > We should replace {{String.format}} with simple concatenation in both > instances. -- This message was sent by Atlassian Jira (v8.3.4#803005)
[wicket] branch master updated: WICKET-6824 Replace slow `String.format` with concatenation
This is an automated email from the ASF dual-hosted git repository. svenmeier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/wicket.git The following commit(s) were added to refs/heads/master by this push: new ad5e81b WICKET-6824 Replace slow `String.format` with concatenation ad5e81b is described below commit ad5e81b83b49ba1b58945cb14df1a63fa508f44a Author: Thomas Heigl AuthorDate: Sun Aug 30 20:42:46 2020 +0200 WICKET-6824 Replace slow `String.format` with concatenation This closes #449 --- .../src/main/java/org/apache/wicket/Component.java | 6 ++- .../wicket/ajax/AbstractDefaultAjaxBehavior.java | 52 +++--- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/wicket-core/src/main/java/org/apache/wicket/Component.java b/wicket-core/src/main/java/org/apache/wicket/Component.java index d72f24e..423355c 100644 --- a/wicket-core/src/main/java/org/apache/wicket/Component.java +++ b/wicket-core/src/main/java/org/apache/wicket/Component.java @@ -2365,9 +2365,11 @@ public abstract class Component { String name = Strings.isEmpty(tag.getNamespace()) ? tag.getName() : tag.getNamespace() + ':' + tag.getName(); + + // prefer concatenation over String#format() for performance response.write( - String.format("<%s id=\"%s\" hidden=\"\" data-wicket-placeholder=\"\">", name, - getAjaxRegionMarkupId(), name)); + "<" + name + " id=\"" + getAjaxRegionMarkupId() + + "\" hidden=\"\" data-wicket-placeholder=\"\">"); } diff --git a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java index 291303f..7da491b 100644 --- a/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java +++ b/wicket-core/src/main/java/org/apache/wicket/ajax/AbstractDefaultAjaxBehavior.java @@ -61,16 +61,16 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior public static final ResourceReference INDICATOR = new PackageResourceReference( AbstractDefaultAjaxBehavior.class, "indicator.gif"); - private static final String DYNAMIC_PARAMETER_FUNCTION_TEMPLATE = "function(attrs){%s}"; - private static final String PRECONDITION_FUNCTION_TEMPLATE = "function(attrs){%s}"; - private static final String COMPLETE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, textStatus){%s}"; - private static final String FAILURE_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, errorMessage, textStatus){%s}"; - private static final String SUCCESS_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, data, textStatus){%s}"; - private static final String AFTER_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; - private static final String BEFORE_SEND_HANDLER_FUNCTION_TEMPLATE = "function(attrs, jqXHR, settings){%s}"; - private static final String BEFORE_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; - private static final String INIT_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; - private static final String DONE_HANDLER_FUNCTION_TEMPLATE = "function(attrs){%s}"; + private static final String DYNAMIC_PARAMETER_FUNCTION_SIGNATURE = "function(attrs)"; + private static final String PRECONDITION_FUNCTION_SIGNATURE = "function(attrs)"; + private static final String COMPLETE_HANDLER_FUNCTION_SIGNATURE = "function(attrs, jqXHR, textStatus)"; + private static final String FAILURE_HANDLER_FUNCTION_SIGNATURE = "function(attrs, jqXHR, errorMessage, textStatus)"; + private static final String SUCCESS_HANDLER_FUNCTION_SIGNATURE = "function(attrs, jqXHR, data, textStatus)"; + private static final String AFTER_HANDLER_FUNCTION_SIGNATURE = "function(attrs)"; + private static final String BEFORE_SEND_HANDLER_FUNCTION_SIGNATURE = "function(attrs, jqXHR, settings)"; + private static final String BEFORE_HANDLER_FUNCTION_SIGNATURE = "function(attrs)"; + private static final String INIT_HANDLER_FUNCTION_SIGNATURE = "function(attrs)"; + private static final String DONE_HANDLER_FUNCTION_SIGNATURE = "function(attrs)"; /** * Subclasses should call super.onBind() @@ -261,46 +261,46 @@ public abstract class AbstractDefaultAjaxBehavior extends AbstractAjaxBehavior CharSequence initHandler = ajaxCallListener.getInitHandler(component); appendListenerHandler(initHandler, attributesJson, AjaxAttributeName.INIT_HANDLER.jsonName(), - INIT_HANDLER_FUNCTION_TEMPLATE); +
[jira] [Commented] (WICKET-6824) Use concatenation instead of String.format for frequently called methods
[ https://issues.apache.org/jira/browse/WICKET-6824?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187314#comment-17187314 ] Thomas Heigl commented on WICKET-6824: -- Created PR: https://github.com/apache/wicket/pull/449 > Use concatenation instead of String.format for frequently called methods > > > Key: WICKET-6824 > URL: https://issues.apache.org/jira/browse/WICKET-6824 > Project: Wicket > Issue Type: Improvement > Components: wicket-core >Affects Versions: 9.0.0 >Reporter: Thomas Heigl >Assignee: Thomas Heigl >Priority: Minor > Attachments: image-2020-08-30-20-34-57-261.png, > image-2020-08-30-20-35-04-970.png > > > Two usages of {{String.format}} frequently show up in my production profiler: > !image-2020-08-30-20-34-57-261.png! > !image-2020-08-30-20-35-04-970.png! > Both methods are potentially called dozens or even hundreds of times for > large pages. > {{String.format}} has horrible performance and should mostly be used for > generating error messages and debug information. For a detailed analysis see: > [https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8] > We should replace {{String.format}} with simple concatenation in both > instances. -- This message was sent by Atlassian Jira (v8.3.4#803005)
[jira] [Created] (WICKET-6824) Use concatenation instead of String.format for frequently called methods
Thomas Heigl created WICKET-6824: Summary: Use concatenation instead of String.format for frequently called methods Key: WICKET-6824 URL: https://issues.apache.org/jira/browse/WICKET-6824 Project: Wicket Issue Type: Improvement Components: wicket-core Affects Versions: 9.0.0 Reporter: Thomas Heigl Assignee: Thomas Heigl Attachments: image-2020-08-30-20-34-57-261.png, image-2020-08-30-20-35-04-970.png Two usages of {{String.format}} frequently show up in my production profiler: !image-2020-08-30-20-34-57-261.png! !image-2020-08-30-20-35-04-970.png! Both methods are potentially called dozens or even hundreds of times for large pages. {{String.format}} has horrible performance and should mostly be used for generating error messages and debug information. For a detailed analysis see: [https://redfin.engineering/java-string-concatenation-which-way-is-best-8f590a7d22a8] We should replace {{String.format}} with simple concatenation in both instances. -- This message was sent by Atlassian Jira (v8.3.4#803005)
[jira] [Commented] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=17187289#comment-17187289 ] Thorsten Schöning commented on WICKET-6823: --- I've attached a quickstart demonstrating the issue by creating two very simple transformers to change the version number rendered on runtime. When attaching only one transformer, the textual phrase "" is found in the rendered output, otherwise it's not. This demonstrates the overall problem, that neither the output of the transformer itself is available, e..g the phrase "bar" in this test, nor any markup after the component the two transformers are applied to. {noformat} String version = getApplication().getFrameworkSettings().getVersion(); Label label = new Label("version", version); label.add(new FooTrans()); //label.add(new BarTrans()); {noformat} Just change the comment about "BarTrans" to make the test succeed or fail. If it fails, the stacktrace already shows where the HTML-output stops as well: {noformat} junit.framework.AssertionFailedError: pattern '' not found in: http://wicket.apache.org;> Apache Wicket Quickstart Apache Wicket Reporting a bug Help us help you: reproduce the bug with the least amount of code create a unit test that shows the bug fix the bug and create a patch attach the result of step 1, 2 or 3 to a https://issues.apache.org/jira/browse/WICKET; target="_blank">JIRA issue profit! Please mention the correct Wicket version: 8.9.0 foo at org.apache.wicket.util.tester.WicketTester.assertResult(WicketTester.java:798) at org.apache.wicket.util.tester.WicketTester.assertContains(WicketTester.java:365) at de.am_soft.TestHomePage.homepageRendersSuccessfully(TestHomePage.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210) {noformat} > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >
[jira] [Updated] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
[ https://issues.apache.org/jira/browse/WICKET-6823?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ] Thorsten Schöning updated WICKET-6823: -- Attachment: multiple_abstract_transformer_behavior.zip > Two instances of AbstractTransformerBehavior on the same component results in > incomplete output. > > > Key: WICKET-6823 > URL: https://issues.apache.org/jira/browse/WICKET-6823 > Project: Wicket > Issue Type: Bug > Components: wicket-core >Affects Versions: 8.9.0 >Reporter: Thorsten Schöning >Priority: Major > Attachments: multiple_abstract_transformer_behavior.zip > > > I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server > or requests, only by using ComponentRenderer. There are two implementations > of AbstractTransformerBehavior to update "colspan" attributes of table cells > and IDs of arbitrary HTML nodes. Both are used on the same component: > {noformat} > resultsCont.add(new DvResultsCont.ColSpanUpdater()); > resultsCont.add(new MkIdReplacer > ( > "th", "id", "td", "headers", > String.format("%d.%s", itemIdx, kindOfDetail) > )); > {noformat} > When only ONE of both behaviours is used, the page renders successfully and > it doesn't make any difference which one is used. If both of those are used > OTOH, the page seems to be rendered at all as well, but some rendered content > is simply missing in the overall output in the end. My component > "resultsCont" renders to a table, so the last markup I have is the following: > {noformat} > > [...] > > {noformat} > In theory, after that table there should be additional content like foots, > closing elements for HTML itself etc. So the current rendering is invalid. > It's important to note, though, that I don't get any exception, the output > simply seems to not contain all data. When enabling DEBUG logging during > rendering, the logs make pretty much clear that Wicket really tries to > continue rendering, but the output is simply missing. > As no exceptions are thrown and output seems to simply be ignored at some > point, I have the feeling the problem is in handling the response objects in > "AbstractTransformerBehavior". All of those assigned transformers to some > component are called before actually rendering anything and change the > response. "Component.java" contains the following code: > {noformat} > /** > * {@link Behavior#beforeRender(Component)} Notify all behaviors that are > assigned to this > * component that the component is about to be rendered. > */ > private void notifyBehaviorsComponentBeforeRender() > { > for (Behavior behavior : getBehaviors()) > { > if (isBehaviorAccepted(behavior)) > { > behavior.beforeRender(this); > } > } > } > {noformat} > Each call to "beforeRender" changes the response and all those changes are > done one after another. This means that the current request to render two > will be that one of the LAST applied transformer only. > {noformat} > @Override > public void beforeRender(Component component) > { > super.beforeRender(component); > final RequestCycle requestCycle = RequestCycle.get(); > // Temporarily replace the web response with a String response > originalResponse = requestCycle.getResponse(); > WebResponse origResponse = (WebResponse)((originalResponse instanceof > WebResponse) > ? originalResponse : null); > BufferedWebResponse tempResponse = newResponse(origResponse); > // temporarily set StringResponse to collect the transformed output > requestCycle.setResponse(tempResponse); > } > {noformat} > Only after all those changes to the current request, content is rendered and > transformed, using the current request AND changing it back to what each > individual transformer believes to be the original request. > {noformat} > @Override > public void afterRender(final Component component) > { > final RequestCycle requestCycle = RequestCycle.get(); > try > { > BufferedWebResponse tempResponse = > (BufferedWebResponse)requestCycle.getResponse(); > if (component instanceof Page && originalResponse instanceof > WebResponse) > { > tempResponse.writeMetaData((WebResponse) > originalResponse); > } > // Transform the data > CharSequence output = transform(component, > tempResponse.getText()); > originalResponse.write(output); > } > catch (Exception ex) > { > throw new WicketRuntimeException("Error while transforming the > output of component: " + > component, ex); >
[jira] [Created] (WICKET-6823) Two instances of AbstractTransformerBehavior on the same component results in incomplete output.
Thorsten Schöning created WICKET-6823: - Summary: Two instances of AbstractTransformerBehavior on the same component results in incomplete output. Key: WICKET-6823 URL: https://issues.apache.org/jira/browse/WICKET-6823 Project: Wicket Issue Type: Bug Components: wicket-core Affects Versions: 8.9.0 Reporter: Thorsten Schöning I'm using Wicket as a renderer for HTML-reports WITHOUT browser, web server or requests, only by using ComponentRenderer. There are two implementations of AbstractTransformerBehavior to update "colspan" attributes of table cells and IDs of arbitrary HTML nodes. Both are used on the same component: {noformat} resultsCont.add(new DvResultsCont.ColSpanUpdater()); resultsCont.add(new MkIdReplacer ( "th", "id", "td", "headers", String.format("%d.%s", itemIdx, kindOfDetail) )); {noformat} When only ONE of both behaviours is used, the page renders successfully and it doesn't make any difference which one is used. If both of those are used OTOH, the page seems to be rendered at all as well, but some rendered content is simply missing in the overall output in the end. My component "resultsCont" renders to a table, so the last markup I have is the following: {noformat} [...] {noformat} In theory, after that table there should be additional content like foots, closing elements for HTML itself etc. So the current rendering is invalid. It's important to note, though, that I don't get any exception, the output simply seems to not contain all data. When enabling DEBUG logging during rendering, the logs make pretty much clear that Wicket really tries to continue rendering, but the output is simply missing. As no exceptions are thrown and output seems to simply be ignored at some point, I have the feeling the problem is in handling the response objects in "AbstractTransformerBehavior". All of those assigned transformers to some component are called before actually rendering anything and change the response. "Component.java" contains the following code: {noformat} /** * {@link Behavior#beforeRender(Component)} Notify all behaviors that are assigned to this * component that the component is about to be rendered. */ private void notifyBehaviorsComponentBeforeRender() { for (Behavior behavior : getBehaviors()) { if (isBehaviorAccepted(behavior)) { behavior.beforeRender(this); } } } {noformat} Each call to "beforeRender" changes the response and all those changes are done one after another. This means that the current request to render two will be that one of the LAST applied transformer only. {noformat} @Override public void beforeRender(Component component) { super.beforeRender(component); final RequestCycle requestCycle = RequestCycle.get(); // Temporarily replace the web response with a String response originalResponse = requestCycle.getResponse(); WebResponse origResponse = (WebResponse)((originalResponse instanceof WebResponse) ? originalResponse : null); BufferedWebResponse tempResponse = newResponse(origResponse); // temporarily set StringResponse to collect the transformed output requestCycle.setResponse(tempResponse); } {noformat} Only after all those changes to the current request, content is rendered and transformed, using the current request AND changing it back to what each individual transformer believes to be the original request. {noformat} @Override public void afterRender(final Component component) { final RequestCycle requestCycle = RequestCycle.get(); try { BufferedWebResponse tempResponse = (BufferedWebResponse)requestCycle.getResponse(); if (component instanceof Page && originalResponse instanceof WebResponse) { tempResponse.writeMetaData((WebResponse) originalResponse); } // Transform the data CharSequence output = transform(component, tempResponse.getText()); originalResponse.write(output); } catch (Exception ex) { throw new WicketRuntimeException("Error while transforming the output of component: " + component, ex); } finally { // Restore the original response object requestCycle.setResponse(originalResponse); } } {noformat} Because all transformers are executed in order at this stage, the FIRST executed transformer works on the content of the request of the LAST one which put requests into place. After applying its own transformation, it puts its own original request in place and the next transformer works on that and puts its own