2

This is my code below, when I execute it shows me the size 3, but when I pop the object out I am getting only 2 objects.

import java.util.*;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class HelloWorldAction extends ActionSupport {

    private static final long serialVersionUID = 1L;
    private String name;

    public String execute() throws Exception {
        ValueStack stack = ActionContext.getContext().getValueStack();
        Map<String, Object> context = new HashMap<String, Object>();

        context.put("key1", new String("This is key1"));
        context.put("key2", new String("This is key2"));
        context.put("key3", new String("This is key3"));
        stack.push(context);

        System.out.println("Size of the valueStack: " + stack.size());

        for (int i = 0; i < stack.size(); i++) {
            System.out.println(i + ": " + stack.pop().toString());
        }
        return "success";
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
 

Please, explain me whether I am doing it wrong?

Wnd I want to know that what are the objects stored in ValueStack and how can I retrieve those objects?

Roman C
  • 49,761
  • 33
  • 66
  • 176
Sachin Singh
  • 49
  • 1
  • 6
  • 1
    You are pushing **one** object onto the value stack: `context` :| – Andrea Ligios Aug 01 '16 at 08:52
  • yes i m pushing only one object and the other object in the value stack is the action object so it means there are only 2 object so the size of the value stack should be 2, but it is giving me 3 as the size of the object, that's what my concern is i want to know why is it showing the size 3 ? – Sachin Singh Aug 01 '16 at 09:51
  • There are multiple things in the value stack. For example, the action itself is pushed onto the stack before hitting the view layer. – Dave Newton Aug 01 '16 at 13:50

2 Answers2

3

You have mistreated the context and a map.

First, you got an action context and valueStack.

Then you created a map called context and pushed it to the stack.

Then you have started iterate over the stack, but the stack is a different object that has context pushed over.

To get your context back from the stack you need to pop() or peek() it from the valueStack. Then you can iterate it as a map.

The code:

context = (Map<String, Object>)stack.pop();
for (Map.Entry<String, Object> entry : context.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

Roman C
  • 49,761
  • 33
  • 66
  • 176
  • actually u took me wrong. what my point is that when i print the size of object it gives 3 as output but when i pop the object from value stack i get only 2 object. Actually want to understand what objects are stored in the value stack and i m only getting 2 object – Sachin Singh Aug 01 '16 at 09:47
  • you print the size of stack, not the size of object in the stack – Roman C Aug 01 '16 at 10:51
  • using stack.pop() i m trying to retrieve the object in the stack. but anyways thanks i got my answer – Sachin Singh Aug 01 '16 at 11:58
  • You should retrieve ( `pop()` ) *only* object that you've pushed, that's the point. – Roman C Aug 01 '16 at 12:00
  • @SachinSingh did you? can you give me a link or may be someone already asked this before? – Roman C Aug 01 '16 at 12:07
  • thanks for this information sir. but in the specification it does not mention anything like this https://struts.apache.org/maven/struts2-core/apidocs/com/opensymphony/xwork2/util/ValueStack.html#pop() – Sachin Singh Aug 01 '16 at 12:10
  • The `valueStack` is generally used on the view layer, so it's important to `pop()` object when it's no longer needed. It's a brief description, more detailed explanation you can find from [this](http://stackoverflow.com/a/26177210/573032) answer. – Roman C Aug 01 '16 at 12:25
  • @SachinSingh Accept the answer. – Roman C Oct 29 '16 at 18:41
2

There are two errors in your code, that are preventing the result to be printed correctly.


Error n.1

i <= stack.size() should be i < stack.size(), otherwise with 3 elements you'll try to print 4 elements (i is 0-based, size() is 1-based).
You are not encountering this error because of error n.2.


Error n.2

System.out.println(i + ": " + stack.pop().toString());

.pop(): Get the object on the top of the stack and remove it from the stack.

You should then store the size before the loop, because otherwise the size of the stack changes at every iteration.

This is what is happening:

for (int i = 0; i <= 3; i++) {

for (int i = 1; i <= 2; i++) {

for (int i = 2; i <= 1; i++) { // not performed. And you don't fall in error n.1.

Working code(s)

int size = stack.size();

for (int i = 0; i < size; i++) {
    System.out.println(i + ": " + stack.pop().toString());
}

This will print the result correctly, however it will alter the value stack; to prevent that, you should loop the value stack's objects from within an iterator, that you can obtain with the getRoot() method:

Iterator itr = stack.getRoot().iterator();
while (itr.hasNext()) {
    System.out.println(itr.next().toString()); 
    // or .getClass().getName(), ReflectionToStringBuilder.toString(), or whatever...
}
Andrea Ligios
  • 49,480
  • 26
  • 114
  • 243
  • thanks for pointing that, but this what i m trying to check whether it throws any exception or not and u ll be glad to know that it was not throwing any exception. another thing u need to note that is i m not using i and peek returns just the top most element in the stack – Sachin Singh Aug 01 '16 at 10:33
  • thanks mate but in case of pop() also it won't throw any exception. but that wasn't my concern and I got my answer by using getroot() method and it gave me the 3 objects that are in the valuestack and those are [{key3=This is key3, key2=This is key2, key1=This is key1}, com.sachin.HelloWorldAction@4e857327, com.opensymphony.xwork2.DefaultTextProvider@1b4b2db7] thanks for help – Sachin Singh Aug 01 '16 at 12:05
  • @SachinSingh You have got the same object and the size didn't change because `valueStack` is thread-safe. You just use another method to retrieve the object but the API is the same, with exception you got a lot of errors in programming Java code. – Roman C Aug 01 '16 at 12:09
  • Not clues on why he's not getting the 3rd element, nor why it's not trying getting a non-existing 4th, then @RomanC. But the whole Q&A is confusing so it could be everything – Andrea Ligios Aug 01 '16 at 12:12
  • 1
    @AndreaLigios u r right. int size = stack.size(); for (int i = 0; i < size; i++) { System.out.println(i + ": " + stack.pop().toString()); } this is what i had used in my application and i m not trying to get the 4th element i was just checking whether it throws an exception or not. I m going to edit the code above in question so that it don't distract other people Even u can try it you will also get 2 elements even if the size of valuestack is showing 3. Anyways thanks for your help – Sachin Singh Aug 01 '16 at 12:15
  • @AndreaLigios The part that is using `for` loop is wrong and should be removed, the question indeed expose XY problem and will be closed as off-topic. – Roman C Aug 01 '16 at 12:31
  • @RomanC: I've tried, it's like I said. It was a shot in the dark, but if you think about it, stack.size() is not returning the size of the stack, is returning the size of the inner CompoundRoot. If it changes, at every iteration a new value is returned for the size. You'd get ConcurrentModificationException while iterating Lists / Maps and removing elements from the collection you're iterating; with value stack, instead, you get this unwanted result :) – Andrea Ligios Aug 01 '16 at 13:23
  • @SachinSingh please remember to **upvote** every useful answer, and **accept** the answer that solved your problem completely, if any. Thanks – Andrea Ligios Aug 01 '16 at 13:35