One way to implement this, without altering Avro, would be to write a renaming schema copier, something like:
public Schema copy(Schema source, Map<String,String> renames);
This would be pretty simple to write. One could construct the renaming table by first walking the schema to find all of the names in it, with a method like:
public Map<String,Schema> getNames(Schema schema);
This would also be simple to write. Then, give a set of schemas, one can maintain a set of all names already seen, and as one adds the schemas to a union, rename any whose names have already been used.
Another approach might be to define scoping rules, e.g., a re-definition might only be visible within itself. This would be confusingly inconsistent, however, since in a protocol we'd like sibling definitions to be visible to one another, but in this case we do not want sibling definitions to be visible to one another. So I prefer the renaming approach.
Note that with renaming, one could use a convention like suffixing names with _X, which one could then remove again later. Or, once namespaces are correctly supported (
AVRO-30), renaming could just change the package.