The solution for was to treat all converted (AttributeConverter) types as mutable so that dirty checking, deep copying and second-level caching all work properly no matter what.
However, treating these as immutable (when they really are) is more efficient. So allow the user some way to indicate whether a converted type is mutable or immutable.
Some initial ideas were:
new optional contract to be implemented by the AttributeConverter impl.
new annotation to be applied to the AttributeConverter impl
To be clear this is isolated to custom Java types generally speaking. Most of the built-in JDK types recognized by Hibernate already have a proper mutability profile on their JavaTypeDescriptor. Even for custom types, some solutions work today:
Certain types (enums, e.g.) are already recognized as immutable.
Add @org.hibernate.annotations.Immutable to the Java type that represents the "domain side" of the conversion.
Explicitly add a JavaTypeDescriptor for the Java type that represents the "domain side" of the conversion.
(1) is the ideal, where some characteristic of the "domain side" Java type indicates that the type is immutable; for example, we know that a (non-@Enumerated) enum is immutable because all enums are immutable. (2) is a actually a variation of (1), and should be preferred over (3) as it is the simpler solution but it requires that the developer control the "domain side" Java type. An example of this approach:
For this PostalAreaConverter we know the "domain side" Java type (PostalArea) is immutable because the presence of the @Immutable annotation tells us it is.
(3) would mean writing a JavaTypeDescriptor for PostalArea and registering that with the JavaTypeDescriptorRegistry. This JavaTypeDescriptor would indicate immutability via JavaTypeDescriptor#getMutabilityPlan