Actually, I did find a way to make this work. It might not be super graceful, but it does work.
So - what I did was to split the DTO classes up as suggested in the link you sent. I kept all of the basic fields and accessors/mutators in the base class but I also kept a JPA-annotated private field without any accessors / modifiers or GeDA annotation (it is essentially invisible to all but reflection). In the extended object I put the same private field, but annotated it with DtoCollection and marked as @Transient. The accessors/modifiers in the extended class take care of updating the base object as well as the local object.
While I know this can create a little extra memory (two collections stored instead of one), these objects will never have large collections. The places where there are large collections are all paged and the page size is managed with a maximum size at the service layer.
Essentially:
@Entity
@Dto
Class UserBaseDto {
@DtoField
private Long id;
@DtoField
private String name;
@ManyToMany
@JoinTable(...)
private Set<RoleBaseDto> roles;
get/setId()...
get/setName()...
}
@Entity
@Dto
class UserDto extends UserBaseDto {
@DtoCollection(value = "roles", dtoBeanKey = "dtoRoleBase",
entityBeanKeys = "entityRole", dtoToEntityMatcher = RoleMatcher.class,
entityGenericType = Role.class, dtoCollectionClass = java.util.HashSet.class,
entityCollectionClass = java.util.HashSet.class)
@Transient
private Set<RoleBaseDto> roles;
get/setRoles{
update super.roles / get super.roles, assign to local and return
}
}
@Entity
@Dto
Class RoleBaseDto {
@DtoField
private Long id;
@DtoField
private String name;
@ManyToMany(mappedBy="roles")
private Set<UserBaseDto> users;
get/setId()...
get/setName()...
}
@Entity
@Dto
class RoleDto extends RoleBaseDto {
@DtoCollection(value = "users", dtoBeanKey = "dtoUserBase",
entityBeanKeys = "entityUser", dtoToEntityMatcher = UserMatcher.class,
entityGenericType = User.class, dtoCollectionClass = java.util.HashSet.class,
entityCollectionClass = java.util.HashSet.class)
@Transient
private Set<UserBaseDto> users;
get/setUsers{
update local and super.users / get super.users, assign to local and return
}
}
This seems to work because 1) the DtoCollection is only marked on the extended class so is only evaluated there and 2) the JPA layer ignores the field in the extension class because of the @Transient annotation.