If you inspect the return value of getPropertyPath(), you’ll find it’a Iterable<Node> and the last element of the iterator is the field name. The following code works for me:
// I only need the first violation
ConstraintViolation<?> violation = ex.getConstraintViolations().iterator().next();
// get the last node of the violation
String field = null;
for (Node node : violation.getPropertyPath()) {
field = node.getName();
}