Uploaded image for project: 'PUBLIC - Liferay Portal Community Edition'
  1. PUBLIC - Liferay Portal Community Edition
  2. LPS-133689

Multi-value PortletRequest parameters contain null instead of an empty string

    Details

      Description

      Portlet 3.0 Requirement

      Section 11.1 of the JSR 362 (Portlet 3.0) Specification states:

      11.1 Portlet Parameters
      Portlet parameters are name-value pairs modeled after servlet request parameters. The parameter name is represented by a String while the value is a String array. The parameter name may not be null.

      The value null is a valid parameter value, both within a parameter values array and when set or returned as a single value. Setting a parameter value to null does not remove the parameter. Similarly, an empty array is a valid parameter value.

      Regarding the specific requirement about the values array:

      null is a valid parameter value ... within a parameter values array

      ... the Portlet 3.0 TCK has a portlet class named PortletParametersTests_SPEC11_1 that tests the requirement.

      Specifically, line 97 sets up the following:

      RenderURL renderURL = portletResp.createRenderURL();
      MutableRenderParameters mutableRenderParams = renderURL.getRenderParameters();
          ...
      mutableRenderParams.setValues("names_nullsok2", null, "notnull", null);
      

      Then on line 239, it tests to see if the invoked RenderURL preserved null as a parameter value in two spots of the array of values:

      values = renderParams.getValues("names_nullsok2");
      if (values == null || values[0] != null || !values[1].equals("notnull") || values[2] != null) {
          result.appendTcDetail("failed to get public render parameters values for names_nullsok2");
          valid = false;
      }
      

      When the URL is rendered by Apache Pluto (the Portlet 3.0 reference implementation), it looks like this:

      http://localhost:9080/pluto/portal/asdf/__pdtck-V3PortletParametersTests.PortletParametersTests_SPEC11_1%213003444%7C0;0/__re0/__rp0;names_private1:one/__rp0;names_nullok1:,/__rp0;names_private2:two/__rp0;names_nullsok2:,:notnull:,/__rp0;names_encode1:url%26enco+ded/__rp0;names_multi:a:b:c/__sp0;0;names_public1:three
      

      The part of the URL that is relevant to this use case is:

      __rp0;names_nullsok2:,:notnull:,
      

      When the RenderURL is invoked, Pluto PortalURLParserImpl class tries to parse the URL, lines 339-354 do the following:

      String[] pVals = values.split(VALUE_DELIM, -1);
      String[] paramValues = new String[0];
      String paramName = "";
      boolean isEmptyArray = false;
      if (pVals.length > 1) {
         if (pVals.length == 2 && pVals[1].equals(VALUE_ARRAY_EMPTY)) {
            isEmptyArray = true;
         }
         for (int i = 0; i < pVals.length; i++){
            if (pVals[i].equals(VALUE_NULL)) {
               pVals[i] = null;
            } else {
               pVals[i] = urlDecode(pVals[i]);
            }
         }
      }
      

      First, it tries to split the String into a String array using VALUE_DELIM (which is a ":" character, resulting in the following String array:

      pVals[0] = ",";
      pVals[1] = "notnull";
      pVals[2] = ",";
      

      It then iterates through the array, and replaces every occurrence of VALUE_NULL (which is a "," character) with the value null. The result is the following String array:

      pVals[0] = null;
      pVals[1] = "notnull";
      pVals[2] = null;
      

      Problem Description

      The Liferay implementation of Portlet 3.0 has a bug such that multi-value request parameters contain null instead of an empty string. The cause of the bug is found in lines 1411-1417 of PortletRequestImpl.java:

      if ((values != null) && (portletSpecMajorVersion >= 3)) {
      	for (int i = 0; i < values.length; i++) {
      		if ((values[i] != null) && values[i].isEmpty()) {
      			values[i] = null;
      		}
      	}
      }
      

      Although this code causes the aforementioned TCK test to pass, it prevents the empty string ("") from being received from the underlying HttpServletRequest as one of the values in the values String array.

      Steps to Reproduce

      1. Deploy the attached lps133689.jar artifact to $LIFERAY_HOME/deploy

      2. Add the "LPS133689" portlet to a widget page

      3. Click on the "Click me to invoke the RenderURL" link

      Expected Results

      The portlet renders the following:

      Test Result: PASS:[null, , notnull, null]
      

      Actual Results

      The portlet renders a failure, perhaps something like the following:

      Test Result: FAIL:[null, null, notnull, null]
      

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              summer.zhang Summer Zhang
              Reporter:
              neil.griffin Neil Griffin
              Participants of an Issue:
              Recent user:
              Clarissa Velazquez
              Engineering Assignee:
              Neil Griffin
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:
                Days since last comment:
                20 weeks, 2 days ago

                  Packages

                  Version Package
                  7.3.10.3 DXP SP3
                  7.3.X
                  7.4.2 CE GA3 DXP 7,4
                  7.4.13 DXP GA1
                  7.4.3.4 CE GA4
                  Master