我需要在我的应用程序中以集合的形式公开一些配置,但是我需要它们不可修改并且我正在寻找实现此目的的最佳方法。
我需要公开此配置以在业务逻辑操作中执行,如
mySet.set1().constains("Value")
app:
my-set:
set-1: 'Value1,Value2'
set-2: 'Value3,Value4'
如果我尝试在记录或这样编写的类中公开它:
@ConfigurationProperties("app.my-set")
public record MySet(Set<String> set1, Set<String> set2) {
}
这 2 个集合是最终的,所以我无法重新分配它们,但我仍然可以修改其中的元素,就像这样:
@SpringBootTest
@Slf4j
class MySetTest {
@Autowired
private MySet mySet;
@Test
void testMutableSet(){
log.info("Initial set: [{}]", mySet);
assertTrue(mySet.set1().contains("Value1") && mySet.set1().contains("Value2"));
assertTrue(mySet.set2().contains("Value3") && mySet.set2().contains("Value4"));
mySet.set1().remove("Value1");
mySet.set2().remove("Value3");
mySet.set1().add("Custom1");
mySet.set2().add("Custom2");
log.info("Final set: [{}]", mySet);
assertFalse(mySet.set1().contains("Value1"));
assertFalse(mySet.set2().contains("Value3"));
assertTrue(mySet.set1().contains("Custom1") && mySet.set1().contains("Value2"));
assertTrue(mySet.set2().contains("Custom2") && mySet.set2().contains("Value4"));
}
}
为了隐藏在类范围之外修改它们的可能性,我使用了一种解决方法: 我实现了返回unmodifyingSet的方法:
@ConfigurationProperties("app.my-set")
public record MySet(Set<String> set1, Set<String> set2) {
public Set<String> set1() {
return Collections.unmodifiableSet(set1);
}
public Set<String> set2() {
return Collections.unmodifiableSet(set2);
}
}
通过这种解决方法,当我需要将其注入到其他类中时,我只能看到 MyImmutableSet 接口,而无法修改 Sets 内的值。
@SpringBootTest
@Slf4j
class MyImmutableSetTest {
@Autowired
private MySet mySet;
@Test
void testImmutable(){
log.info("Initial set: [{}]", mySet);
assertTrue(mySet.set1().contains("Value1") && mySet.set1().contains("Value2"));
assertTrue(mySet.set2().contains("Value3") && mySet.set2().contains("Value4"));
assertThrows(UnsupportedOperationException.class, () -> mySet.set1().remove("Value1"));
assertThrows(UnsupportedOperationException.class, () -> mySet.set2().remove("Value3"));
assertThrows(UnsupportedOperationException.class, () -> mySet.set1().add("Custom1"));
assertThrows(UnsupportedOperationException.class, () -> mySet.set2().add("Custom2"));
log.info("Final set: [{}]", mySet);
assertFalse(mySet.set1().contains("Custom1"));
assertFalse(mySet.set2().contains("Custom2"));
assertTrue(mySet.set1().contains("Value1") && mySet.set1().contains("Value2"));
assertTrue(mySet.set2().contains("Value3") && mySet.set2().contains("Value4"));
}
}
我真的不喜欢这种解决方法,所以我正在寻找一种更干净的解决方案来提高可维护性,也许还需要一些注释。 我已经尝试过使用仅公开两组的界面并从记录中删除
public
访问修饰符,但它看起来比唯一的记录更糟糕。我自己所做的是使用记录构造函数简写来替换输入:
@ConfigurationProperties("app.my-set")
public record MySet(Set<String> set1, Set<String> set2) {
public MySet {
set1 = Set.copyOf(set1);
set2 = Set.copyOf(set2);
}
}
如果需要,你可以制作这些
null-safe
:set1 = set1 == null ? Set.of() : Set.copyOf(set1);