Resolve 5336 Mdm Link History Would Fail If Provided with Unknown Ids On Postgres (#5337)
* - Added checks in MdmLinkDaoJpaImpl to make sure no empty IN clauses are sent to database. - Implemented tests for the above change. * modified changelog
This commit is contained in:
parent
a2204654df
commit
c3ff3dae82
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5336
|
||||||
|
jira: SMILE-7406
|
||||||
|
title: "Previously, on PostgreSQL, the $mdm-link-history operation would fail if all ids provided to a parameter are
|
||||||
|
unknown, and the error will persist for all subsequent requests. This is now fixed."
|
|
@ -40,6 +40,7 @@ import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.collections4.ListUtils;
|
import org.apache.commons.collections4.ListUtils;
|
||||||
|
import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hibernate.envers.AuditReader;
|
import org.hibernate.envers.AuditReader;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
|
@ -371,21 +372,39 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao<JpaPid, MdmLink> {
|
||||||
final AuditQueryCreator auditQueryCreator = myAuditReader.createQuery();
|
final AuditQueryCreator auditQueryCreator = myAuditReader.createQuery();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final AuditCriterion goldenResourceIdCriterion = AuditEntity.property(GOLDEN_RESOURCE_PID_NAME)
|
final AuditCriterion goldenResourceIdCriterion = buildAuditCriterionOrNull(
|
||||||
.in(convertToLongIds(theMdmHistorySearchParameters.getGoldenResourceIds()));
|
theMdmHistorySearchParameters.getGoldenResourceIds(), GOLDEN_RESOURCE_PID_NAME);
|
||||||
final AuditCriterion resourceIdCriterion = AuditEntity.property(SOURCE_PID_NAME)
|
|
||||||
.in(convertToLongIds(theMdmHistorySearchParameters.getSourceIds()));
|
final AuditCriterion resourceIdCriterion =
|
||||||
|
buildAuditCriterionOrNull(theMdmHistorySearchParameters.getSourceIds(), SOURCE_PID_NAME);
|
||||||
|
|
||||||
final AuditCriterion goldenResourceAndOrResourceIdCriterion;
|
final AuditCriterion goldenResourceAndOrResourceIdCriterion;
|
||||||
|
|
||||||
if (!theMdmHistorySearchParameters.getGoldenResourceIds().isEmpty()
|
if (!theMdmHistorySearchParameters.getGoldenResourceIds().isEmpty()
|
||||||
&& !theMdmHistorySearchParameters.getSourceIds().isEmpty()) {
|
&& !theMdmHistorySearchParameters.getSourceIds().isEmpty()) {
|
||||||
|
|
||||||
|
// Make sure the criterion does not contain empty IN clause, e.g. id IN (), which postgres (likely other
|
||||||
|
// sql servers) do not like. Directly return empty result instead.
|
||||||
|
if (ObjectUtils.anyNull(goldenResourceIdCriterion, resourceIdCriterion)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
goldenResourceAndOrResourceIdCriterion =
|
goldenResourceAndOrResourceIdCriterion =
|
||||||
AuditEntity.and(goldenResourceIdCriterion, resourceIdCriterion);
|
AuditEntity.and(goldenResourceIdCriterion, resourceIdCriterion);
|
||||||
|
|
||||||
} else if (!theMdmHistorySearchParameters.getGoldenResourceIds().isEmpty()) {
|
} else if (!theMdmHistorySearchParameters.getGoldenResourceIds().isEmpty()) {
|
||||||
|
|
||||||
|
if (ObjectUtils.anyNull(goldenResourceIdCriterion)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
goldenResourceAndOrResourceIdCriterion = goldenResourceIdCriterion;
|
goldenResourceAndOrResourceIdCriterion = goldenResourceIdCriterion;
|
||||||
|
|
||||||
} else if (!theMdmHistorySearchParameters.getSourceIds().isEmpty()) {
|
} else if (!theMdmHistorySearchParameters.getSourceIds().isEmpty()) {
|
||||||
|
|
||||||
|
if (ObjectUtils.anyNull(resourceIdCriterion)) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
goldenResourceAndOrResourceIdCriterion = resourceIdCriterion;
|
goldenResourceAndOrResourceIdCriterion = resourceIdCriterion;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException(Msg.code(2298)
|
throw new IllegalArgumentException(Msg.code(2298)
|
||||||
+ "$mdm-link-history Golden resource and source query IDs cannot both be empty.");
|
+ "$mdm-link-history Golden resource and source query IDs cannot both be empty.");
|
||||||
|
@ -420,6 +439,12 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao<JpaPid, MdmLink> {
|
||||||
.collect(Collectors.toUnmodifiableList());
|
.collect(Collectors.toUnmodifiableList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AuditCriterion buildAuditCriterionOrNull(
|
||||||
|
List<IIdType> theMdmHistorySearchParameterIds, String theProperty) {
|
||||||
|
List<Long> longIds = convertToLongIds(theMdmHistorySearchParameterIds);
|
||||||
|
return longIds.isEmpty() ? null : AuditEntity.property(theProperty).in(longIds);
|
||||||
|
}
|
||||||
|
|
||||||
private MdmLinkWithRevision<MdmLink> buildRevisionFromObjectArray(Object[] theArray) {
|
private MdmLinkWithRevision<MdmLink> buildRevisionFromObjectArray(Object[] theArray) {
|
||||||
final Object mdmLinkUncast = theArray[0];
|
final Object mdmLinkUncast = theArray[0];
|
||||||
final Object revisionUncast = theArray[1];
|
final Object revisionUncast = theArray[1];
|
||||||
|
|
|
@ -20,6 +20,8 @@ import org.hl7.fhir.r4.model.Enumerations;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.hl7.fhir.r4.model.Practitioner;
|
import org.hl7.fhir.r4.model.Practitioner;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -276,6 +278,179 @@ public class MdmLinkDaoSvcTest extends BaseMdmR4Test {
|
||||||
assertEquals(2, actualMdmLinkRevisions.size(), "Both Patient/p123 and Practitioner/p123 should be returned");
|
assertEquals(2, actualMdmLinkRevisions.size(), "Both Patient/p123 and Practitioner/p123 should be returned");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {"allUnknown", "someUnknown"})
|
||||||
|
public void testHistoryForUnknownIdsSourceIdOnly(String mode) {
|
||||||
|
// setup
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients1 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 3);
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients2 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 4);
|
||||||
|
|
||||||
|
MdmHistorySearchParameters mdmHistorySearchParameters = null;
|
||||||
|
List<MdmLinkWithRevision<MdmLink>> expectedMdLinkRevisions = null;
|
||||||
|
switch (mode) {
|
||||||
|
// $mdm-link-history?resourceId=Patient/unknown
|
||||||
|
case "allUnknown" -> {
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters().setSourceIds(List.of("unknown"));
|
||||||
|
expectedMdLinkRevisions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/1,Patient/2,Patient/unknown
|
||||||
|
case "someUnknown" -> {
|
||||||
|
List<String> resourceIdsWithSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getSourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
resourceIdsWithSomeUnknown.add("unknown");
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters().setSourceIds(resourceIdsWithSomeUnknown);
|
||||||
|
|
||||||
|
final JpaPid goldenResourceId1 = mdmLinksWithLinkedPatients1.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid goldenResourceId2 = mdmLinksWithLinkedPatients2.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid sourceId1_1 = mdmLinksWithLinkedPatients1.get(0).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_1 = mdmLinksWithLinkedPatients2.get(0).getSourcePersistenceId();
|
||||||
|
expectedMdLinkRevisions = List.of(
|
||||||
|
buildMdmLinkWithRevision(1, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId1, sourceId1_1),
|
||||||
|
buildMdmLinkWithRevision(4, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute
|
||||||
|
final List<MdmLinkWithRevision<MdmLink>> actualMdmLinkRevisions = myMdmLinkDaoSvc.findMdmLinkHistory(mdmHistorySearchParameters);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assert expectedMdLinkRevisions != null;
|
||||||
|
assertMdmRevisionsEqual(expectedMdLinkRevisions, actualMdmLinkRevisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {"allUnknown", "someUnknown"})
|
||||||
|
public void testHistoryForUnknownIdsGoldenResourceIdOnly(String mode) {
|
||||||
|
// setup
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients1 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 3);
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients2 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 4);
|
||||||
|
|
||||||
|
MdmHistorySearchParameters mdmHistorySearchParameters = null;
|
||||||
|
List<MdmLinkWithRevision<MdmLink>> expectedMdLinkRevisions = null;
|
||||||
|
switch (mode) {
|
||||||
|
// $mdm-link-history?goldenResourceId=Patient/unknown
|
||||||
|
case "allUnknown" -> {
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters().setGoldenResourceIds(List.of("unknown"));
|
||||||
|
expectedMdLinkRevisions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
// $mdm-link-history?goldenResourceId=Patient/1,Patient/2,Patient/unknown
|
||||||
|
case "someUnknown" -> {
|
||||||
|
List<String> resourceIdsWithSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getGoldenResourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
resourceIdsWithSomeUnknown.add("unknown");
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters().setGoldenResourceIds(resourceIdsWithSomeUnknown);
|
||||||
|
|
||||||
|
final JpaPid goldenResourceId1 = mdmLinksWithLinkedPatients1.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid goldenResourceId2 = mdmLinksWithLinkedPatients2.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid sourceId1_1 = mdmLinksWithLinkedPatients1.get(0).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId1_2 = mdmLinksWithLinkedPatients1.get(1).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId1_3 = mdmLinksWithLinkedPatients1.get(2).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_1 = mdmLinksWithLinkedPatients2.get(0).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_2 = mdmLinksWithLinkedPatients2.get(1).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_3 = mdmLinksWithLinkedPatients2.get(2).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_4 = mdmLinksWithLinkedPatients2.get(3).getSourcePersistenceId();
|
||||||
|
expectedMdLinkRevisions = List.of(
|
||||||
|
buildMdmLinkWithRevision(1, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId1, sourceId1_1),
|
||||||
|
buildMdmLinkWithRevision(2, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId1, sourceId1_2),
|
||||||
|
buildMdmLinkWithRevision(3, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId1, sourceId1_3),
|
||||||
|
buildMdmLinkWithRevision(4, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_1),
|
||||||
|
buildMdmLinkWithRevision(5, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_2),
|
||||||
|
buildMdmLinkWithRevision(6, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_3),
|
||||||
|
buildMdmLinkWithRevision(7, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_4)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute
|
||||||
|
final List<MdmLinkWithRevision<MdmLink>> actualMdmLinkRevisions = myMdmLinkDaoSvc.findMdmLinkHistory(mdmHistorySearchParameters);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assert expectedMdLinkRevisions != null;
|
||||||
|
assertMdmRevisionsEqual(expectedMdLinkRevisions, actualMdmLinkRevisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@ValueSource(strings = {
|
||||||
|
"allUnknownSourceId",
|
||||||
|
"allUnknownGoldenId",
|
||||||
|
"allUnknownBoth",
|
||||||
|
"someUnknownSourceId",
|
||||||
|
"someUnknownGoldenId",
|
||||||
|
"someUnknownBoth"
|
||||||
|
})
|
||||||
|
public void testHistoryForUnknownIdsBothSourceAndGoldenResourceId(String mode) {
|
||||||
|
// setup
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients1 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 3);
|
||||||
|
final List<MdmLink> mdmLinksWithLinkedPatients2 = createMdmLinksWithLinkedPatients(MdmMatchResultEnum.MATCH, 4);
|
||||||
|
|
||||||
|
MdmHistorySearchParameters mdmHistorySearchParameters = null;
|
||||||
|
final JpaPid goldenResourceId1 = mdmLinksWithLinkedPatients1.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid goldenResourceId2 = mdmLinksWithLinkedPatients2.get(0).getGoldenResourcePersistenceId();
|
||||||
|
final JpaPid sourceId1_1 = mdmLinksWithLinkedPatients1.get(0).getSourcePersistenceId();
|
||||||
|
final JpaPid sourceId2_1 = mdmLinksWithLinkedPatients2.get(0).getSourcePersistenceId();
|
||||||
|
List<MdmLinkWithRevision<MdmLink>> expectedMdLinkRevisions = List.of(
|
||||||
|
buildMdmLinkWithRevision(1, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId1, sourceId1_1),
|
||||||
|
buildMdmLinkWithRevision(4, RevisionType.ADD, MdmMatchResultEnum.MATCH, goldenResourceId2, sourceId2_1)
|
||||||
|
);
|
||||||
|
switch (mode) {
|
||||||
|
// $mdm-link-history?resourceId=Patient/unknown&goldenResourceId=Patient/1,Patient/2
|
||||||
|
case "allUnknownSourceId" -> {
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(List.of("unknown"))
|
||||||
|
.setGoldenResourceIds(new ArrayList<>(getIdsFromMdmLinks(MdmLink::getGoldenResourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0))));
|
||||||
|
expectedMdLinkRevisions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/1,Patient/2&goldenResourceId=Patient/unknown
|
||||||
|
case "allUnknownGoldenId" -> {
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(new ArrayList<>(getIdsFromMdmLinks(MdmLink::getSourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0))))
|
||||||
|
.setGoldenResourceIds(List.of("unknown"));
|
||||||
|
expectedMdLinkRevisions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/unknown&goldenResourceId=Patient/unknownGolden
|
||||||
|
case "allUnknownBoth" -> {
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(List.of("unknown"))
|
||||||
|
.setGoldenResourceIds(List.of("unknownGolden"));
|
||||||
|
expectedMdLinkRevisions = new ArrayList<>();
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/1,Patient/2,Patient/unknown&goldenResourceId=Patient/3,Patient/4
|
||||||
|
case "someUnknownSourceId" -> {
|
||||||
|
List<String> sourceIdsWithSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getSourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
sourceIdsWithSomeUnknown.add("unknown");
|
||||||
|
List<String> goldenResourceIds = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getGoldenResourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(sourceIdsWithSomeUnknown)
|
||||||
|
.setGoldenResourceIds(goldenResourceIds);
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/1,Patient/2&goldenResourceId=Patient/3,Patient/4,Patient/unknown
|
||||||
|
case "someUnknownGoldenId" -> {
|
||||||
|
List<String> sourceIds = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getSourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
List<String> goldenResourceIdsSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getGoldenResourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
goldenResourceIdsSomeUnknown.add("unknown");
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(sourceIds)
|
||||||
|
.setGoldenResourceIds(goldenResourceIdsSomeUnknown);
|
||||||
|
}
|
||||||
|
// $mdm-link-history?resourceId=Patient/1,Patient/2,Patient/unknown&goldenResourceId=Patient/3,Patient/4,Patient/unknownGolden
|
||||||
|
case "someUnknownBoth" -> {
|
||||||
|
List<String> sourceIdsSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getSourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
sourceIdsSomeUnknown.add("unknown");
|
||||||
|
List<String> goldenResourceIdsSomeUnknown = new ArrayList<>(getIdsFromMdmLinks(MdmLink::getGoldenResourcePersistenceId, mdmLinksWithLinkedPatients1.get(0), mdmLinksWithLinkedPatients2.get(0)));
|
||||||
|
goldenResourceIdsSomeUnknown.add("unknownGolden");
|
||||||
|
mdmHistorySearchParameters = new MdmHistorySearchParameters()
|
||||||
|
.setSourceIds(sourceIdsSomeUnknown)
|
||||||
|
.setGoldenResourceIds(goldenResourceIdsSomeUnknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute
|
||||||
|
final List<MdmLinkWithRevision<MdmLink>> actualMdmLinkRevisions = myMdmLinkDaoSvc.findMdmLinkHistory(mdmHistorySearchParameters);
|
||||||
|
|
||||||
|
// verify
|
||||||
|
assert expectedMdLinkRevisions != null;
|
||||||
|
assertMdmRevisionsEqual(expectedMdLinkRevisions, actualMdmLinkRevisions);
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
private static List<String> getIdsFromMdmLinks(Function<MdmLink, JpaPid> getIdFunction, MdmLink... mdmLinks) {
|
private static List<String> getIdsFromMdmLinks(Function<MdmLink, JpaPid> getIdFunction, MdmLink... mdmLinks) {
|
||||||
return Arrays.stream(mdmLinks)
|
return Arrays.stream(mdmLinks)
|
||||||
|
|
Loading…
Reference in New Issue