javajsonstruts2struts-config

JSON response in struts


I have defined the result type for my action as follows.

<package name="nonrest-actions" extends="struts-default,json-default"
    namespace="/service">


    <action name="waterUsageByAggregation" class="action.nonrest.WaterUsageAction"
        method="usageBreakUp">
        <result name="success" type="json" >
            <param name="root">usageBreakUp</param>
            <param name="noCache">true</param>
        </result>
        <result name="success">NotImplemented.html</result>
        <result name="input">NotImplemented.html</result>
    </action>

</package>

My action class has the following members

// input parameters
private int storageId;
private Date fromDate;
private Date toDate;
private int aggregationId;

// Output
private Map<String, String> usageBreakUp = new HashMap<>();

But the JSON response I get is not rooted at usageBreakUp.

    {
   "actionErrors":[

   ],
   "actionMessages":[

   ],
   "aggregationId":2,
   "errorMessages":[

   ],
   "errors":{

   },
   "fieldErrors":{

   },
   "fromDate":null,
   "locale":{
      "ISO3Country":"USA",
      "ISO3Language":"eng",
      "country":"US",
      "displayCountry":"United States",
      "displayLanguage":"English",
      "displayName":"English (United States)",
      "displayScript":"",
      "displayVariant":"",
      "extensionKeys":[

      ],
      "language":"en",
      "script":"",
      "unicodeLocaleAttributes":[

      ],
      "unicodeLocaleKeys":[

      ],
      "variant":""
   },
   "storageId":1,
   "texts":null,
   "toDate":null,
   "usageBreakUp":{
      "3rd Floor":"20",
      "Ist Floor":"20",
      "4th Floor":"40",
      "2nd Floor":"20"
   }
}

What am I missing here?

EDIT : Here is my entire action class

public class WaterUsageAction extends ActionSupport
{
    private final static int NO_DATA = -1;

    /**
     * Action method which gives the break up of water usage amongst child
     * aggregations
     */

    // Input parameters
    private int storageId;
    private Date fromDate;
    private Date toDate;
    private int aggregationId;

    // Output
    private Map<String, String> usageBreakUp = new HashMap<>();

    // http://localhost:8080/SWNBackend/service/waterUsageByAggregation.json?aggregationId=2&storageId=1
    public String usageBreakUp()
    {
        AggregationDAO aggregationDAO = new AggregationDAO();
        Aggregation aggregation = aggregationDAO.findByIdLazy(aggregationId);

        for (int childAggregationId : aggregation.getAggregationIds())
        {
            Aggregation childAggregation = aggregationDAO
                    .findByIdLazy(childAggregationId);
            String usageString = String.valueOf(getUsage(
                    childAggregation.getId(), fromDate, toDate));
            if (usageString.equals(String.valueOf(NO_DATA)))
                usageString = "No Data";
            usageBreakUp.put(childAggregation.getName(), usageString);
        }
        return SUCCESS;
    }

    /*************************************************************************/

    /**
     * Calculates water usage for the specified aggregation in the specified
     * time frame
     * 
     * @param aggregationId
     * @param from
     * @param to
     * @return
     */
    private int getUsage(int aggregationId, Date from, Date to)
    {
        int usage = 0;

        // The nodes through which water flows into this aggregation
        List<SWNNode> entryNodes = WaterNetwork.getInstance().getEntryNodes(
                aggregationId);
        if (entryNodes.isEmpty())
            throw new RuntimeException(
                    "SWN configuration error : No entry points for aggregation "
                            + aggregationId);

        for (SWNNode entryNode : entryNodes)
        {
            int tmpUsage = getUsage(entryNode, from, to);
            if (tmpUsage == NO_DATA)
                return NO_DATA;
            usage += tmpUsage;
        }
        return usage;
    }

    /**
     * Calculates water usage w.r.t to the flow through the specified node
     * 
     * @param entryNode
     * @param from
     * @param to
     * @return
     */
    private int getUsage(SWNNode entryNode, Date from, Date to)
    {
        // Base case
        if (entryNode.getAsset().hasFlowSensor())
        {
            return 20;
            // TODO : ImplementSensorsDataDAO
            /*
             * return (new SensorsDataDAO()).getFlowData(entryNode.getAsset()
             * .getFlowSensorId(), fromDate, toDate);
             */
        }
        else if (entryNode.getChildren().isEmpty())
            return NO_DATA;

        // Recursively find the usage
        int usage = 0;
        for (SWNNode node : entryNode.getChildren())
        {
            int tmpUsage = getUsage(node, from, to);
            if (tmpUsage == NO_DATA)
                return NO_DATA;
            usage += tmpUsage;
        }
        return usage;
    }

    public Map<String, String> getUsageBreakUp()
    {
        return usageBreakUp;
    }

    public void setUsageBreakUp(Map<String, String> usageBreakUp)
    {
        this.usageBreakUp = usageBreakUp;
    }

    public int getStorageId()
    {
        return storageId;
    }

    public void setStorageId(int storageId)
    {
        this.storageId = storageId;
    }

    public Date getFromDate()
    {
        return fromDate;
    }

    public void setFromDate(Date fromDate)
    {
        this.fromDate = fromDate;
    }

    public Date getToDate()
    {
        return toDate;
    }

    public void setToDate(Date toDate)
    {
        this.toDate = toDate;
    }

    public int getAggregationId()
    {
        return aggregationId;
    }

    public void setAggregationId(int aggregationId)
    {
        this.aggregationId = aggregationId;
    }
}

EDIT : Find the source here.


Solution

  • EDIT

    You have defined twice the SUCCESS result for your action.