FasterXML / jackson-core

Core part of Jackson that defines Streaming API as well as basic shared abstractions
Apache License 2.0
2.27k stars 799 forks source link

`JsonPointer` parsing of '~' not followed by "0" or "1" unexpected #1361

Closed slz30 closed 2 weeks ago

slz30 commented 2 weeks ago

JsonPointer is compatible with non escaped characters~, but this compatibility fails when~is located at the end of FieldName and followed by /. Here is a simple example

public static void main(String[] args) {
        ObjectMapper om = new ObjectMapper();
        ObjectNode jo = om.createObjectNode();
        ArrayNode nums = om.createArrayNode().add(0).add(1);
        jo.set("num~s",nums);
        JsonPointer jp = JsonPointer.compile("/num~s/0");
        System.out.println(jo.at(jp)); //print 0

        jo.remove("num~s");
        jo.set("nums~",nums);
        jp = JsonPointer.compile("/nums~");
        System.out.println(jo.at(jp)); //print [0,1]

        jo.remove("num~s");
        jo.set("nums~",nums);
        jp = JsonPointer.compile("/nums~/0");
        System.out.println(jo.at(jp).isMissingNode()); // is missingNode
    }
cowtowncoder commented 2 weeks ago

Ok, this took a while to parse. My first though is that:

  1. I am not sure "/nums~/0" (or "/nums~") is valid JSON Pointer expression: intent by spec is for ~0 and ~1 be mean escaped ~ and / characters, respectively. Spec is unclear on this point tho
  2. Given that Jackson does not fail (thrown exception), it seems it should work as you except, and there is a problem to solve
  3. Without looking at code, I am guessing that ~/ combination is taken to mean roughly same as ~1, that is, escaped / character -- so it'd look for key "nums/0" hence not matching array at "nums~

Changing behavior is slightly backwards incompatible so fix would need to go in 2.19.

cowtowncoder commented 2 weeks ago

Ok, so, behavior for tilde NOT followed by either '0' or '1' is technically unspecified, as far as I understand. The current implementation basically considers tilde to be "general escape", so if any other character than '0' or '1' follows, that character is used as-is, and tilde is skipped/ignored. That is why the case here fails: key to look for is "nums/0".

I think I will change the behavior to instead include "lone" tildes as regular characters, so test as given would pass. This does seem like slightly more correct behavior.