First approach could be, expose Op.setPath(path) method. On invocation of multi(ops) api, will iterate and modify directly to the client Op objects by prepending chRoot. I feel, this appraoch will break the immutability of Op and is modifying the Op passed by the client. Hence it will not able to reuse Op objects on a non-chRoot clients.
Second approach could be, provide Op.clone(String path) method. On invocation of multi(ops) api, will iterate and create a new Op object by prepending chRoot path, and retains Op client object as immutable. Made clone(path) as abstract and will be overidden for new operation type. IMO, the second one could be the better way.
I have attached the patch based on the second appraoch, please review the changes and test cases.
Case: Also I have seen the 'path' validation is missing for the multi(ops) api. IMO, we can raise a new task/subtask and address the issue separately, since it involves method signature modification of Op apis by throwing 'KeeperException'.
If everyone agrees, I would like to help by doing the changes.