[ 
https://issues.apache.org/jira/browse/WICKET-2384?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Tsutomu YANO updated WICKET-2384:
---------------------------------

    Description: 
When I uses component.info() method to display a message, my program stopped by 
OutOfMemoryError or StackOverflowError. 

I create a sample application to show this problem. Open attached tar.gz 
file(including a maven project) and run. 
check 'submit continuously' checkbox and click 'register' button. 

The program will display current session size continuously on console. the size 
will be increased, and finally program will be 
stopped with OutOfMemoryError or StackOverflowError. 

But if you changes only one line, this program will not be stopped. 

---original code--- 
    private SubmitLink insertLink = new SubmitLink("insertLink") { 
        public void onSubmit() { 
            info("message"); 
            setResponsePage(new Test(testFormBean)); 
            Session session = Session.get(); 
            long size = session.getSizeInBytes(); 
            LOGGER.info("SESSION SIZE: {}", size); 
        } 
    }; 
--------------------- 

---changed---------- 
    private SubmitLink insertLink = new SubmitLink("insertLink") { 
        public void onSubmit() { 
            Session.get().info("message");  //CHANGED!!! 
            setResponsePage(new Test(testFormBean)); 
            Session session = Session.get(); 
            long size = session.getSizeInBytes(); 
            LOGGER.info("SESSION SIZE: {}", size); 
        } 
    }; 
-------------------- 

   so component's info() method is the reason of this problem. If you commented 
out 'info()' line, this program never crashed.

   We found out the reason of this problem in a static inner class 
'MessageListView' in FeedbackPanel.
  MessageListView uses annonimous inner class of Model (named ad 
'replacementModel'), and it imports a FeedbackMessage object from 

enclosing instance. FeedbackPanel holds this annonimous inner class and the 
annonimous inner class holds a FeedbackMessage.

  When we use component's info() method, the component is assigned into 
FeedbackMessage object as a 'reporter' object. so, all of 

FeedbackMessage objects have a component instance inside of himself as 
'reporter' (only one exception: if you use Session.get().info() 

method instead of component's info() method, 'reporter' object become null).

  All already-displayed FeedbackMessages will be purged at 'detach' time from 
Session object. But FeedbackPanel holds FeedbackMessages. 

So when page is serialized, all FeedbackMessages, all 'reporter' components is 
serialized. This is the reason of this problem.

  We can solve this problem if we do not hold FeedbackMessage instance in the 
annnonimous inner class.
change the code of FeedbackPanel as bellow (this code is based on FeedbackPanel 
class of wicket 1.4-rc7, line 70):

---- original code -----
@Override
protected void populateItem(final ListItem<FeedbackMessage> listItem)
{
    final FeedbackMessage message = listItem.getModelObject();
    message.markRendered();
    final IModel<String> replacementModel = new Model<String>()
    {
        private static final long serialVersionUID = 1L;

        /**
         * Returns feedbackPanel + the message level, eg 'feedbackPanelERROR'. 
This is used
         * as the class of the li / span elements.
         * 
         * @see org.apache.wicket.model.IModel#getObject()
         */
        @Override
        public String getObject()
        {
            return getCSSClass(message);
        }
    };

    final Component label = newMessageDisplayComponent("message", message);
    final AttributeModifier levelModifier = new AttributeModifier("class", 
replacementModel);
    label.add(levelModifier);
    listItem.add(levelModifier);
    listItem.add(label);
}
--------------------


---- fixed code ----
@Override
protected void populateItem(final ListItem<FeedbackMessage> listItem)
{
    //FIXED message must not be 'final'. It must not be used in inner class.
    //If message could be used in inner class, the instance could be hold by
    //inner class tacitly and never cleared at detach time and will be 
serialized.
    FeedbackMessage message = listItem.getModelObject();
    message.markRendered();
    final IModel<String> replacementModel = new Model<String>()
    {
        private static final long serialVersionUID = 1L;

        /**
         * Returns feedbackPanel + the message level, eg 'feedbackPanelERROR'. 
This is used
         * as the class of the li / span elements.
         * 
         * @see org.apache.wicket.model.IModel#getObject()
         */
        @Override
        public String getObject()
        {
            //FIXED -- retrieve a FeedbackMessage object from ListView's Model.
            //         never hold it.
            @SuppressWarnings("unchecked")
            List<FeedbackMessage> list = (List<FeedbackMessage>) 
MessageListView.this.getDefaultModelObject();
            FeedbackMessage feedbackMessage = null;
            int index = listItem.getIndex();
            if(index < list.size()) {
                feedbackMessage = list.get(index);
            }
            if(feedbackMessage == null) return "";
            return getCSSClass(feedbackMessage);
            //UNTIL HERE
        }
    };

    final Component label = newMessageDisplayComponent("message", message);
    final AttributeModifier levelModifier = new AttributeModifier("class", 
replacementModel);
    label.add(levelModifier);
    listItem.add(levelModifier);
    listItem.add(label);
}
--------------------


  was:
When I uses component.info() method to display a message, my program stopped by 
OutOfMemoryError or StackOverflowError. 
on both of wicket 1.4-rc7 and wicket 1.3.6.

I create a sample application to show this problem. Open attached tar.gz 
file(including a maven project) and run. 
check 'submit continuously' checkbox and click 'register' button. 

The program will display current session size continuously on console. the size 
will be increased, and finally program will be 
stopped with OutOfMemoryError or StackOverflowError. 

But if you changes only one line, this program will not be stopped. 

---original code--- 
    private SubmitLink insertLink = new SubmitLink("insertLink") { 
        public void onSubmit() { 
            info("message"); 
            setResponsePage(new Test(testFormBean)); 
            Session session = Session.get(); 
            long size = session.getSizeInBytes(); 
            LOGGER.info("SESSION SIZE: {}", size); 
        } 
    }; 
--------------------- 

---changed---------- 
    private SubmitLink insertLink = new SubmitLink("insertLink") { 
        public void onSubmit() { 
            Session.get().info("message");  //CHANGED!!! 
            setResponsePage(new Test(testFormBean)); 
            Session session = Session.get(); 
            long size = session.getSizeInBytes(); 
            LOGGER.info("SESSION SIZE: {}", size); 
        } 
    }; 
-------------------- 

   so component's info() method is the reason of this problem. If you commented 
out 'info()' line, this program never crashed.

   We found out the reason of this problem in a static inner class 
'MessageListView' in FeedbackPanel.
  MessageListView uses annonimous inner class of Model (named ad 
'replacementModel'), and it imports a FeedbackMessage object from 

enclosing instance. FeedbackPanel holds this annonimous inner class and the 
annonimous inner class holds a FeedbackMessage.

  When we use component's info() method, the component is assigned into 
FeedbackMessage object as a 'reporter' object. so, all of 

FeedbackMessage objects have a component instance inside of himself as 
'reporter' (only one exception: if you use Session.get().info() 

method instead of component's info() method, 'reporter' object become null).

  All already-displayed FeedbackMessages will be purged at 'detach' time from 
Session object. But FeedbackPanel holds FeedbackMessages. 

So when page is serialized, all FeedbackMessages, all 'reporter' components is 
serialized. This is the reason of this problem.

  We can solve this problem if we do not hold FeedbackMessage instance in the 
annnonimous inner class.
change the code of FeedbackPanel as bellow (this code is based on FeedbackPanel 
class of wicket 1.4-rc7, line 70):

---- original code -----
@Override
protected void populateItem(final ListItem<FeedbackMessage> listItem)
{
        final FeedbackMessage message = listItem.getModelObject();
        message.markRendered();
        final IModel<String> replacementModel = new Model<String>()
        {
                private static final long serialVersionUID = 1L;

                /**
                 * Returns feedbackPanel + the message level, eg 
'feedbackPanelERROR'. This is used
                 * as the class of the li / span elements.
                 * 
                 * @see org.apache.wicket.model.IModel#getObject()
                 */
                @Override
                public String getObject()
                {
                        return getCSSClass(message);
                }
        };

        final Component label = newMessageDisplayComponent("message", message);
        final AttributeModifier levelModifier = new AttributeModifier("class", 
replacementModel);
        label.add(levelModifier);
        listItem.add(levelModifier);
        listItem.add(label);
}
--------------------


---- fixed code ----
@Override
protected void populateItem(final ListItem<FeedbackMessage> listItem)
{
        //FIXED message must not be 'final'. It must not be used in inner class.
        //If message could be used in inner class, the instance could be hold by
        //inner class tacitly and never cleared at detach time and will be 
serialized.
        FeedbackMessage message = listItem.getModelObject();
        message.markRendered();
        final IModel<String> replacementModel = new Model<String>()
        {
                private static final long serialVersionUID = 1L;

                /**
                 * Returns feedbackPanel + the message level, eg 
'feedbackPanelERROR'. This is used
                 * as the class of the li / span elements.
                 * 
                 * @see org.apache.wicket.model.IModel#getObject()
                 */
                @Override
                public String getObject()
                {
                        //FIXED -- retrieve a FeedbackMessage object from 
ListView's Model.
                        //         never hold it.
                        @SuppressWarnings("unchecked")
                        List<FeedbackMessage> list = (List<FeedbackMessage>) 
MessageListView.this.getDefaultModelObject();
                        FeedbackMessage feedbackMessage = null;
                        int index = listItem.getIndex();
                        if(index < list.size()) {
                                feedbackMessage = list.get(index);
                        }
                        if(feedbackMessage == null) return "";
                        return getCSSClass(feedbackMessage);
                        //UNTIL HERE
                }
        };

        final Component label = newMessageDisplayComponent("message", message);
        final AttributeModifier levelModifier = new AttributeModifier("class", 
replacementModel);
        label.add(levelModifier);
        listItem.add(levelModifier);
        listItem.add(label);
}
--------------------



changed tab to 4 spaces.

> OutOfMemoryError occur for memory leak on FeedbackPanel & FeedbackMessages
> --------------------------------------------------------------------------
>
>                 Key: WICKET-2384
>                 URL: https://issues.apache.org/jira/browse/WICKET-2384
>             Project: Wicket
>          Issue Type: Bug
>          Components: wicket
>    Affects Versions: 1.3.6, 1.4-RC7
>         Environment: reproduceable on wicket-1.4-rc7(current newest) and 
> wicket-1.3.6(current newest release of 1.3 series). tested on Windows XP and 
> Mac OS X
>            Reporter: Tsutomu YANO
>            Priority: Critical
>         Attachments: wickettestapp.tar.gz
>
>
> When I uses component.info() method to display a message, my program stopped 
> by OutOfMemoryError or StackOverflowError. 
> I create a sample application to show this problem. Open attached tar.gz 
> file(including a maven project) and run. 
> check 'submit continuously' checkbox and click 'register' button. 
> The program will display current session size continuously on console. the 
> size will be increased, and finally program will be 
> stopped with OutOfMemoryError or StackOverflowError. 
> But if you changes only one line, this program will not be stopped. 
> ---original code--- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             info("message"); 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> --------------------- 
> ---changed---------- 
>     private SubmitLink insertLink = new SubmitLink("insertLink") { 
>         public void onSubmit() { 
>             Session.get().info("message");  //CHANGED!!! 
>             setResponsePage(new Test(testFormBean)); 
>             Session session = Session.get(); 
>             long size = session.getSizeInBytes(); 
>             LOGGER.info("SESSION SIZE: {}", size); 
>         } 
>     }; 
> -------------------- 
>    so component's info() method is the reason of this problem. If you 
> commented out 'info()' line, this program never crashed.
>    We found out the reason of this problem in a static inner class 
> 'MessageListView' in FeedbackPanel.
>   MessageListView uses annonimous inner class of Model (named ad 
> 'replacementModel'), and it imports a FeedbackMessage object from 
> enclosing instance. FeedbackPanel holds this annonimous inner class and the 
> annonimous inner class holds a FeedbackMessage.
>   When we use component's info() method, the component is assigned into 
> FeedbackMessage object as a 'reporter' object. so, all of 
> FeedbackMessage objects have a component instance inside of himself as 
> 'reporter' (only one exception: if you use Session.get().info() 
> method instead of component's info() method, 'reporter' object become null).
>   All already-displayed FeedbackMessages will be purged at 'detach' time from 
> Session object. But FeedbackPanel holds FeedbackMessages. 
> So when page is serialized, all FeedbackMessages, all 'reporter' components 
> is serialized. This is the reason of this problem.
>   We can solve this problem if we do not hold FeedbackMessage instance in the 
> annnonimous inner class.
> change the code of FeedbackPanel as bellow (this code is based on 
> FeedbackPanel class of wicket 1.4-rc7, line 70):
> ---- original code -----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>     final FeedbackMessage message = listItem.getModelObject();
>     message.markRendered();
>     final IModel<String> replacementModel = new Model<String>()
>     {
>         private static final long serialVersionUID = 1L;
>         /**
>          * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>          * as the class of the li / span elements.
>          * 
>          * @see org.apache.wicket.model.IModel#getObject()
>          */
>         @Override
>         public String getObject()
>         {
>             return getCSSClass(message);
>         }
>     };
>     final Component label = newMessageDisplayComponent("message", message);
>     final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>     label.add(levelModifier);
>     listItem.add(levelModifier);
>     listItem.add(label);
> }
> --------------------
> ---- fixed code ----
> @Override
> protected void populateItem(final ListItem<FeedbackMessage> listItem)
> {
>     //FIXED message must not be 'final'. It must not be used in inner class.
>     //If message could be used in inner class, the instance could be hold by
>     //inner class tacitly and never cleared at detach time and will be 
> serialized.
>     FeedbackMessage message = listItem.getModelObject();
>     message.markRendered();
>     final IModel<String> replacementModel = new Model<String>()
>     {
>         private static final long serialVersionUID = 1L;
>         /**
>          * Returns feedbackPanel + the message level, eg 
> 'feedbackPanelERROR'. This is used
>          * as the class of the li / span elements.
>          * 
>          * @see org.apache.wicket.model.IModel#getObject()
>          */
>         @Override
>         public String getObject()
>         {
>             //FIXED -- retrieve a FeedbackMessage object from ListView's 
> Model.
>             //         never hold it.
>             @SuppressWarnings("unchecked")
>             List<FeedbackMessage> list = (List<FeedbackMessage>) 
> MessageListView.this.getDefaultModelObject();
>             FeedbackMessage feedbackMessage = null;
>             int index = listItem.getIndex();
>             if(index < list.size()) {
>                 feedbackMessage = list.get(index);
>             }
>             if(feedbackMessage == null) return "";
>             return getCSSClass(feedbackMessage);
>             //UNTIL HERE
>         }
>     };
>     final Component label = newMessageDisplayComponent("message", message);
>     final AttributeModifier levelModifier = new AttributeModifier("class", 
> replacementModel);
>     label.add(levelModifier);
>     listItem.add(levelModifier);
>     listItem.add(label);
> }
> --------------------

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to