Ampersand value escaped always in REST via GEL
search cancel

Ampersand value escaped always in REST via GEL

book

Article ID: 280542

calendar_today

Updated On: 07-09-2024

Products

Clarity PPM On Premise Clarity PPM SaaS

Issue/Introduction

It is possible to enter an ampersand (&) in a String via Clarity and the stored value in the database will be '&'. For example, entering 'A&B' will store 'A&B' in the database.
Similarly, when using the REST API, the same value will also be stored as 'A&B'.
However, doing the same REST API calls via a GEL script will always escape the characters stored in the database to 'A&B'.

Steps to Reproduce:

  1. Create a new process that has a GEL script to perform a PATCH request to a String attribute to modify its value to 'A&B'.

Sample script:

(Pre-requisites - adjust the script if any pre-requisite is changed):

    • user: 'user', with all rights
    • password: 'password'
    • 'mystring' String attribute in Project, API enabled as 'z_mystring'
    • Adjust URL of a project instance with the right hostname/project instance: https://<hostname>/ppm/rest/v1/projects/<instance>

<gel:script xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wss="http://www.boomi.com/connector/wss" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xog="http://www.niku.com/xog" xmlns:x="jelly:org.apache.commons.jelly.tags.xml.XMLTagLibrary" xmlns:util="jelly:util" xmlns:sql="jelly:sql" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:jelly="jelly:core" xmlns:nikuq="http://www.niku.com/xog/Query" xmlns:gel="jelly:com.niku.union.gel.GELTagLibrary" xmlns:file="jelly:com.niku.union.gel.FileTagLibrary" xmlns:core="jelly:core">

    <!--***************************************Get the session from the system Start ***********************************-->
    <gel:parameter var="gel_host_user" default="user"/>
    <gel:parameter var="gel_host_pass" default="password"/>
    <gel:setDataSource dbId="niku"/>
    <!--Set parameter here End -->
    <!--***************************************Get the session from the system End ***********************************-->

    <!-- Generate SessionID -->
    <core:new className="com.niku.union.security.DefaultSecurityIdentifier" var="secId"/>
    <core:invokeStatic var="userSessionCtrl" className="com.niku.union.security.UserSessionControllerFactory" method="getInstance"/>
    <core:set var="secId" value="${userSessionCtrl.init(gel_host_user, secId)}"/>
    <core:set var="sessionID" value="${secId.getSessionId()}"/>

    <core:choose>
        <core:when test="${sessionID == null}">
            <gel:log level="ERROR">Cannot login to Clarity XOG. Check username.</gel:log>
        </core:when>
        <core:otherwise>
            <gel:log>SessionID: ${sessionID}</gel:log>
        </core:otherwise>
    </core:choose>

    <!--core:invoke method="setHeader" on="${patch}"> <core:arg type="java.lang.String" value="Cookie"/>
<core:arg type="java.lang.String" value="${v_Cookie}"/> </core:invoke-->
    <core:new var="patch" className="org.apache.http.client.methods.HttpPatch">
        <core:arg value="https://<hostname>/ppm/rest/v1/projects/<instance>" type="java.lang.String"/>
    </core:new>

    <core:invoke on="${patch}" method="setHeader">
        <core:arg value="Authorization" type="java.lang.String"/>
        <core:arg value="Basic dXNlcjpwYXNzd29yZA==" type="java.lang.String"/>
    </core:invoke>

    <core:invoke on="${patch}" method="setHeader">
        <core:arg value="Content-Type" type="java.lang.String"/>
        <core:arg value="application/json" type="java.lang.String"/>
    </core:invoke>
    
    <core:set var="createProject" escapeText="false"><![CDATA[{"z_mystring":"A&B"}]]></core:set>
    <!-- <core:set var="createProject" escapeText="false">{"code": "${row.CODE}", "name": "${row.NAME}", "description":"${row.DESCRIPTION}" }</core:set> -->
    <core:new var="entity" className="org.apache.http.entity.StringEntity">
        <core:arg value="${createProject}" type="java.lang.String"/>
    </core:new>
    <gel:log>entity: ${entity}</gel:log>

    <core:invoke on="${patch}" method="setEntity">
        <core:arg value="${entity}" type="org.apache.http.entity.StringEntity"/>
    </core:invoke>
    <gel:log>patch: ${patch}</gel:log>

    <core:invokeStatic var="httpclient" className="org.apache.http.impl.client.HttpClients" method="createDefault"/>
    <core:invoke var="response" on="${httpclient}" method="execute">
        <core:arg value="${patch}" type="org.apache.http.client.methods.HttpPatch"/>
    </core:invoke>
    <gel:log>response: ${response}</gel:log>

    <core:invoke var="entityResponse" on="${response}" method="getEntity"/>
    <core:invoke var="ResponseStatus" on="${response}" method="getStatusLine"/>
    <gel:log>ResponseStatus getProtocolVersion: ${ResponseStatus.getProtocolVersion()}</gel:log>
    <gel:log>ResponseStatus getReasonPhrase: ${ResponseStatus.getReasonPhrase()}</gel:log>
    <gel:log>ResponseStatus getStatusCode: ${ResponseStatus.getStatusCode()}</gel:log>
    <gel:log>entityResponse: ${entityResponse}</gel:log>
    <core:set var="void" value="${response.close()}"/>

    <gel:log>exception::${exception}</gel:log>
</gel:script>

  1. Check the value stored in the database.

Expected Results: Value stored is 'A&B' - same as when using Clarity or the REST API without a GEL script.

Actual Results: Value stored is 'A&amp;B'.

Environment

Any Clarity supported version.

Cause

According to the Expected Results, the script is not correct:

<core:set var="createProject" escapeText="false"><![CDATA[{"z_mystring":"A&B"}]]></core:set>

The way the createProject variable is declared, the variable's content will get encoded (replacing & with &amp;).

Resolution

To avoid the encoding, the variable needs to be declared as follows:

<core:set var="createProject" encode="0"><![CDATA[{"z_mystring":"A&B"}]]></core:set>

Additional Information

core:set - Setting Variables

This tag sets a variable from the result of an expression.

encode

When set to:

  • “1”, the body of the tag is encoded as XML text. When "<", ">" and "&" are encountered in the tag body, they are encoded as "&lt;", "&gt;" and "&amp;" respectively.
  • “0”, the body is not encoded.

Use this only if this tag is specified with no value so that the text body of this tag can be used as the body.

Type: Boolean