To be clear, it seems like a nice boiler-plate avoidance technique (which Java could always use more of). But you're implying that there's some other significant underlying problem this solves and I don't see it.
Also, unmodifiableCollection doesn't make the collection you pass in immutable; it creates a new object through which you can access it as long as you don't modify it. Anybody holding a reference to the original object can still change the object.
I think you can even somewhat break the collection by changing objects inside it if doing that changes their hashcode (for sets and dictionaries, such a change may have to reinsert the item in the collection to make sure that you can still retrieve it)
If you weren't using this library, you could achieve something similar with, e.g.,
someImmutableSet = Collections.unmodifiableSet(new HashSet<E>(someSet));
I think this library really is about making immutable objects accessible, i.e., taking away the boiler plate. Hand-writing immutable (and potentially mutable) implementations on top of interfaces for a whole set of DTOs is super annoying.In order for a class to be immutable, all its fields need to be be immutable and final. Immutability got to be recursive.
Also, in Java, the class should be final, otherwise nothing prevents anyone from extending it and pass a mutable data structure instead of the immutable one you'd expect
Edit : added the "in java", as we could imagine another language where immutable doesn't require objects to be final.