如何建议让 Immutables 以这种方式构建此对象

How would it be advised to get Immutables to build this object with this sort

如何让 Immutables 生成具有这种

的 class
public class IdentifiedUserDetails implements UserDetails, CredentialsContainer, Identified<UUID> {
    private static final long serialVersionUID = 4905378177558522349L;

    private final UUID id;
    private final String username;
    private final Set<GrantedAuthority> authorities;
    private boolean accountNonExpired = true;
    private boolean accountNonLocked = true;
    private boolean credentialsNonExpired = true;
    private boolean enabled = true;
    private String password;

    IdentifiedUserDetails( final UUID id, final String username, final String password ) {
        this.id = Objects.requireNonNull( id );
        this.username = Objects.requireNonNull( username );
        this.password = Objects.requireNonNull( password );
        this.authorities = Collections.unmodifiableSet( sortAuthorities( Collections.emptySet() ) );
    }

    private static SortedSet<GrantedAuthority> sortAuthorities(
        final Collection<? extends GrantedAuthority> authorities ) {
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        return authorities.stream()
            .filter( Objects::nonNull )
            .collect( Collectors.toCollection( () -> {
                return new TreeSet<GrantedAuthority>(
                    Comparator.nullsFirst( Comparator.comparing( GrantedAuthority::getAuthority ) ) );
            } ) );
    }
}

注意:空集是从某些外部数据源传入的真实集的占位符,我还没有开始填充它,但我会在某个时候填充,并且排序是在 spring 安全性中,您应该假定排序需要应用于将传递给不可变构建器的任何集合。

鉴于我理解您想要实现的目标,您可以使用不可变注释处理器实现这一目标的方式有很多变体;)

Immutables 支持开箱即用的 SortedSet,但仅使用自然排序(参见 @Value.NaturalOrder@Value.ReverseOrder)。如果你想应用特殊的比较器,Immutables 将只允许你自己构建集合并将其设置到构建器上。从这个例子来看,希望排序是特定于对象实现的东西,所以我会跳到其他选项。

使用 @Value.Check 方法启用对象的 normalization/canonicalization 功能非常强大(但有些容易出错)。指南中对其进行了描述:http://immutables.github.io/immutable.html#normalization。但是,使用规范化有点复杂,因为需要检查 set/collection 是否已经排序。

最后,我会提出另一种更简单的方法,我已将其用于类似目的。 @Value.Derived 注释允许您在对象构建期间构建数据的替代视图。在这种情况下,将使用集合作为初始化缓冲区和该数据的计算替代视图。计算将在构造期间发生,并且不可变对象在那之后永远不会改变。我们将尝试使用访问名和属性名来使它看起来更漂亮。这是示例:

@Value.Immutable
public abstract class IdentifiedUserDetails implements UserDetails, CredentialsContainer, Identified<UUID> {
    private static final long serialVersionUID = 4905378177558522349L;

    public abstract UUID getId();
    public abstract String getUsername();
    public abstract String getPassword();
    // other attributes omitted for brevity
    // ...

    abstract @SkipNulls List<GrantedAuthority> authority();

    @Value.Derived
    public SortedSet<GrantedAuthority> getAuthorities() {
        return authority().stream()
                .collect(Collectors.toCollection(() -> {
                    return new TreeSet(
                            Comparator.nullsFirst(Comparator.comparing(GrantedAuthority::getAuthority)));
                }));
    }
}

public static void demonstration(GrantedAuthority ga1, GrantedAuthority ga2) {

    IdentifiedUserDetails details =
            ImmutableIdentifiedUserDetails.builder()
                    .id(UUID.randomUUID())
                    .username("Name")
                    .password("String")
                    //...
                    .addAuthority(ga1)
                    .addAuthority(ga2)
                    .build();

    SortedSet<GrantedAuthority> sortedAuthorities = details.getAuthorities();
}

P.S。 @SkipNulls 是一种 BYOAnnotation。如果需要,创建它,它会被一个简单的名字识别。