Is this merge sort code good enough?
General comments


you have 'good' mid-finding code: int mid = lo + (hi - lo) / 2; This is fancy code, and, if you have not learned why it is done this way, then you should read up on the midpoint bug in Java.
your algorithm generally looks sound. It works


The basic premise of your sort is good. The code is neat, and, if you know the merge-sort, it is readable, and does the right sort of things at the right times.

With just your code in front of me, I would say 'good job'. To make it better, I would recommend that:


you make your code conform to the standard usage in Java, where you would have two methods:

MergeSort.sort(int[] data);
MergeSort.sort(int[] data, offset, length);


Java typically uses a 'length' argument, instead of a 'high' argument. In the case of the MergeSort, the 'high' variation is more useful, so I would recommend making your current method private, and then adding a new recursion-wrapping frontend to the code that makes it conform to typical Java method calls.


About the aux

This is the second reason to consider wrapping your current sort-entry method in to a calling method.... something like:

public static void sort(int[] data) {
    sort(data, 0, data.length);
}

public static void sort(int[] data, int offset, int length) {
    int[] aux = new int[data.length]; // smarter implementation can be used for if length != data.length
    recursiveSort(data, aux, offset, offset + length);
}


Where the method recursiveSort is the method you currently have as sort.

The reason for doing the aux in the calling method is for memory efficiency. At some point you will need to do the final merge, which will require the entire data array to fit in to a memory 'copy', the aux. You will also do many more smaller merge sorts requiring a smaller size of memory. If you are going to need the large space anyway, you may as well create it in the beginning, and reuse it many times, which is better than creating many small aux which never get reused.