The documentation says the values() method returns the number of matches but it doesn't seem to be the case since in your example it returns undef for both a non-existent element and a null one. Since you check for defined(), they both return false.
What you can do is call values() in list context and check for the number of matches. The non-existent entry should have none and null should have a single undef entry.
my @values = $json_path[$i]->values($json);
if (@values > 0) {
print("exists\n");
}
else {
print("does not exist\n")
}