Skip to content

Single-quoted string arguments to path functions are dropped or corrupted; only double quotes work #1078

Description

@haskiindahouse

Version / environment

  • json-path master @ HEAD (line numbers verified against source); latest release json-path 3.0.0 hits the same code path.
  • JVM: any (Java 8+). Default JSON provider.

Description

JsonPath accepts single-quoted string literals in filter predicates, e.g. $[?(@.name == 'foo')]. Inside function argument lists the compiler recognizes only double quotes. A single-quoted string argument never gets typed as a JSON string parameter: as a standalone argument it yields an empty result, and when mixed with path arguments the quote characters leak into the output.

Steps to reproduce

import com.jayway.jsonpath.*;

// Standalone string arg: double quotes work, single quotes vanish
JsonPath.read("{}", "$.concat(\"hello\")"); // "hello"
JsonPath.read("{}", "$.concat('hello')");   // ""  (argument dropped)

// Mixed with path args on {"x":"P","y":"Q"}: the single quote leaks in
String doc = "{\"x\":\"P\",\"y\":\"Q\"}";
JsonPath.read(doc, "$.concat($.x,\"-\",$.y)"); // "P-Q"   (correct)
JsonPath.read(doc, "$.concat($.x,'-',$.y)");   // "P-'Q"  (corrupted)

Observed output

$.concat("hello")        => [hello]
$.concat('hello')        => []
$.concat($.x,"-",$.y)    => P-Q
$.concat($.x,'-',$.y)    => P-'Q

Expected

Single-quoted string arguments behave like double-quoted ones, matching filter-predicate string handling: 'hello' is the string hello, and '-' is the string -.

Actual

A single-quoted standalone argument produces an empty string. A single-quoted argument alongside path arguments keeps its quote characters, yielding P-'Q instead of P-Q.

Root cause

json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java, the function-parameter reader.

Parameter-type detection (line 308) recognizes only DOUBLE_QUOTE, so a leading single quote never sets the parameter type to JSON:

308:  if (c == OPEN_BRACE || isDigit(c) || DOUBLE_QUOTE == c || MINUS == c) {
309:      type = ParamType.JSON;
310:  }

The quote-grouping switch (lines 317–324) adjusts groupQuote for DOUBLE_QUOTE alone:

317:  case DOUBLE_QUOTE:
318:      if (priorChar != '\\' && groupQuote > 0) { groupQuote--; }
319:      else { groupQuote++; }
320:      break;

SINGLE_QUOTE is defined at line 42 ('\'') and used elsewhere in the compiler, but neither the type check nor the grouping switch references it.

Suggested fix

Handle SINGLE_QUOTE alongside DOUBLE_QUOTE in both places:

  • add || SINGLE_QUOTE == c to the type check at line 308, and
  • add a case SINGLE_QUOTE: to the grouping switch that adjusts groupQuote the same way the DOUBLE_QUOTE case does.

Found via property-based & differential bug-hunting, part of an effort to scale PBT (DepTyCheck-based) testing across the OSS ecosystem.

If this is intended / by-design: I'm really sorry, please just close it — no need to flag or ban me. I'm trying to scale property-based testing across the whole ecosystem and my publishing agents may have gotten this one wrong. I read every issue and follow up on each.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions