【问题标题】:SonarQube: "Store a copy of "productAllergenInfos""SonarQube:“存储“productAllergenInfos”的副本”
【发布时间】:2021-11-25 05:58:23
【问题描述】:

我有以下 DTO:

@Data
@RequiredArgsConstructor
public class MenuItemExpandedDTO {
private UUID uuid;
private List<ModifierGroupDTO> modifierGroupDtoList;
private List<AllergenInfo> allergenInfoList;

public MenuItemExpandedDTO(
        PropertiesDTO propertiesDto,
        List<ModifierGroupDTO> modifierGroupDtoList,
        List<AllergenInfo> allergenInfoList
) {
    this.uuid = propertiesDto.getUuid();
    this.modifierGroupDtoList = modifierGroupDtoList;
    this.allergenInfoList = allergenInfoList;
  }
}

在 SonarQube 分析中,由于allergenInfoList 的说明,我得到了一个漏洞

“消息:存储 allergenInfoList 的副本”

所以,我不确定问题出在哪里,但在修复此错误之前,我想知道该代码有什么问题?在某些页面中,建议初始化列表,例如private List&lt;AllergenInfo&gt; allergenInfoList = Collections.emptyList()。但这不是我在项目中遵循的方式。那么,这段代码有什么问题呢?

【问题讨论】:

标签: java sonarqube dto sonarqube-scan sonarqube-ops


【解决方案1】:

SonarQube 告诉您在构造函数中接收Lists 时要小心。为什么?因为调用者持有对 List 的引用,如果它不是不可变的,它可以使用它执行以下操作:

  1. 通过添加或删除元素来更改List 内容,实际上会影响您的MenuItemExpandedDTO
  2. 如果List 中包含的对象不是不可变的,请更改它们。这意味着可以更改 List 中的 AllergenInfo 对象,从而影响您的 MenuItemExpandedDTO 对象。

要解决 1.,您可以按照 SonarQube 的建议简单地存储 List 的副本:

public MenuItemExpandedDTO(
        PropertiesDTO propertiesDto,
        List<ModifierGroupDTO> modifierGroupDtoList,
        List<AllergenInfo> allergenInfoList
) {
    this.uuid = propertiesDto.getUuid();
    this.modifierGroupDtoList = new ArrayList<>(modifierGroupDtoList);
    this.allergenInfoList = new ArrayList<>(allergenInfoList);
  }
}

解决 2. 更棘手,最简单和更可靠的解决方案是使用不可变对象。您可以在https://www.baeldung.com/java-immutable-object 阅读有关此内容以及如何设计类以便拥有不可变对象的更多信息。

public class MenuItemExpandedDTO {
    private final UUID uuid;
    private final List<ModifierGroupDTO> modifierGroupDtoList;
    private final List<AllergenInfo> allergenInfoList;

    public MenuItemExpandedDTO(PropertiesDTO propertiesDto,
                               List<ModifierGroupDTO> modifierGroupDtoList,
                               List<AllergenInfo> allergenInfoList) {
        this.uuid = propertiesDto.getUuid();
        this.modifierGroupDtoList = new ArrayList<>(modifierGroupDtoList);
        this.allergenInfoList = new ArrayList<>(allergenInfoList);
    }

    public UUID getUuid() {
        return UUID;
    }

    public List<ModifierGroupDTO> getModifierGroupDtoList() {
        return new ArrayList<>(modifierGroupDtoList);
    }

    public List<AllergenInfo> getAllergenInfoList() {
        return new ArrayList<>(allergenInfoList);
    }
}

请记住,ModifierGroupDTOAllergenInfo 也必须是不可变的,以便 MenuItemExpandedDTO 是 100% 不可变的。

【讨论】:

  • 1. 非常感谢您的精彩解释。我从未使用过这种用法,例如this.modifierGroupDtoList = new ArrayList&lt;&gt;(modifierGroupDtoList),我一般用this.modifierGroupDtoList = new ArrayList&lt;&gt;()。那么,this.modifierGroupDtoList = new ArrayList&lt;&gt;(modifierGroupDtoList) 是什么意思呢?我认为这意味着将modifierGroupDtoList 分配给this.modifierGroupDtoList。这是真的吗?
  • 您是否建议像baeldung.com/java-immutable-object 中提到的那样,在解决问题 1 上解决问题 2?
  • 它将包含modifierGroupDtoList 内容的新List 分配给this.modifierGroupDtoList,这样您就有了一个与提供的列表不同的列表(只有列表,而不是其中的对象)。这意味着您必须同时解决 1. 和 2. 问题,如果您想 100% 确保没有其他人与 List 混淆。
  • 非常感谢,投了赞成票。您能否还提供一个示例,使用我的答案中的代码来展示 Tackling 2
  • 完成。请检查我编辑的答案;)
猜你喜欢
  • 2021-07-16
  • 2012-06-28
  • 2015-08-22
  • 2019-09-26
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多