diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobProgress.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobProgress.java index ee0f14d50f0f..72e4dab9e21a 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobProgress.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobProgress.java @@ -47,6 +47,7 @@ import lombok.*; import lombok.experimental.Accessors; import org.hisp.dhis.feedback.ErrorCode; +import org.hisp.dhis.tracker.imports.validation.ValidationCode; /** * @@ -147,6 +148,14 @@ default void addError( addError(code, uid, type, List.of(args)); } + default void addError( + @Nonnull ValidationCode code, + @CheckForNull String uid, + @Nonnull String type, + String... args) { + addError(code, uid, type, List.of(args)); + } + default void addError( @Nonnull ErrorCode code, @CheckForNull String uid, @@ -156,6 +165,15 @@ default void addError( // default is to not collect errors } + default void addError( + @Nonnull ValidationCode code, + @CheckForNull String uid, + @Nonnull String type, + @Nonnull List args) { + // is overridden by a tracker that collects errors + // default is to not collect errors + } + /* * Tracking API: */ @@ -580,7 +598,7 @@ final class Progress { @Nonnull @JsonProperty @JsonInclude(JsonInclude.Include.NON_EMPTY) - private final Map>> errors; + private final Map>> errors; public Progress() { this.sequence = new ConcurrentLinkedDeque<>(); @@ -590,7 +608,7 @@ public Progress() { @JsonCreator public Progress( @Nonnull @JsonProperty("sequence") Deque sequence, - @CheckForNull @JsonProperty("errors") Map>> errors) { + @CheckForNull @JsonProperty("errors") Map>> errors) { this.sequence = sequence; this.errors = errors == null ? Map.of() : errors; } @@ -609,7 +627,7 @@ public boolean hasErrors() { return !errors.isEmpty(); } - public Set getErrorCodes() { + public Set getErrorCodes() { return errors.values().stream() .flatMap(e -> e.keySet().stream()) .collect(toUnmodifiableSet()); @@ -620,7 +638,7 @@ public Set getErrorCodes() { @Accessors(chain = true) final class Error { - @Nonnull @JsonProperty private final ErrorCode code; + @Nonnull @JsonProperty private final String code; /** The object that has the error */ @Nonnull @JsonProperty private final String id; @@ -641,7 +659,7 @@ final class Error { @JsonCreator public Error( - @Nonnull @JsonProperty("code") ErrorCode code, + @Nonnull @JsonProperty("code") String code, @Nonnull @JsonProperty("id") String id, @Nonnull @JsonProperty("type") String type, @Nonnull @JsonProperty("args") List args) { diff --git a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobRunErrorsParams.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobRunErrorsParams.java index f7d0f28c74e1..7c26002f7b84 100644 --- a/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobRunErrorsParams.java +++ b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/scheduling/JobRunErrorsParams.java @@ -72,4 +72,6 @@ public class JobRunErrorsParams { /** The {@link JobType} with errors to select, any match combined */ @CheckForNull private List type; + + boolean includeInput = false; } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java b/dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java similarity index 100% rename from dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java rename to dhis-2/dhis-api/src/main/java/org/hisp/dhis/tracker/imports/validation/ValidationCode.java diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java index 28adb9f5c462..f846855180d6 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobConfigurationService.java @@ -27,6 +27,8 @@ */ package org.hisp.dhis.scheduling; +import static org.hisp.dhis.jsontree.JsonBuilder.createArray; +import static org.hisp.dhis.scheduling.JobType.TRACKER_IMPORT_JOB; import static org.hisp.dhis.scheduling.JobType.values; import com.fasterxml.jackson.annotation.JsonProperty; @@ -40,6 +42,7 @@ import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; @@ -49,7 +52,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -72,6 +74,7 @@ import org.hisp.dhis.schema.Property; import org.hisp.dhis.setting.SettingKey; import org.hisp.dhis.setting.SystemSettingManager; +import org.hisp.dhis.tracker.imports.validation.ValidationCode; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -256,48 +259,69 @@ public List getStaleConfigurations(int staleForSeconds) { @Override @Transactional(readOnly = true) public List findJobRunErrors(@Nonnull JobRunErrorsParams params) { - Function toObject = - json -> { - JsonObject obj = JsonMixed.of(json); - List flatErrors = new ArrayList<>(); - JsonObject errors = obj.getObject("errors"); - errors - .node() - .members() - .forEach( - byObject -> - byObject - .getValue() - .members() - .forEach( - byCode -> - byCode - .getValue() - .elements() - .forEach( - error -> { - ErrorCode code = - ErrorCode.valueOf( - JsonMixed.of(error).getString("code").string()); - Object[] args = - JsonMixed.of(error) - .getArray("args") - .stringValues() - .toArray(new String[0]); - String msg = - MessageFormat.format(code.getMessage(), args); - flatErrors.add( - error - .extract() - .addMembers(e -> e.addString("message", msg))); - }))); - return JsonMixed.of( - errors - .node() - .replaceWith( - JsonBuilder.createArray(arr -> flatErrors.forEach(arr::addElement)))); - }; - return jobConfigurationStore.findJobRunErrors(params).map(toObject).toList(); + return jobConfigurationStore + .findJobRunErrors(params) + .map(json -> errorEntryWithMessages(json, params)) + .toList(); + } + + private JsonObject errorEntryWithMessages(String json, JobRunErrorsParams params) { + JsonObject entry = JsonMixed.of(json); + List flatErrors = new ArrayList<>(); + JobType type = entry.getString("type").parsed(JobType::valueOf); + String fileResourceId = entry.getString("file").string(); + JsonObject errors = entry.getObject("errors"); + String errorCodeNamespace = + type == TRACKER_IMPORT_JOB + ? ValidationCode.class.getSimpleName() + : ErrorCode.class.getSimpleName(); + errors + .node() + .members() + .forEach( + byObject -> + byObject + .getValue() + .members() + .forEach( + byCode -> + byCode + .getValue() + .elements() + .forEach(error -> flatErrors.add(errorWithMessage(type, error))))); + + return JsonMixed.of( + errors + .node() + .replaceWith(createArray(arr -> flatErrors.forEach(arr::addElement))) + .addMembers( + obj -> + obj.addString("codes", errorCodeNamespace) + .addMember("input", getJobInput(params, fileResourceId)))); + } + + private JsonNode getJobInput(JobRunErrorsParams params, String fileResourceId) { + if (!params.isIncludeInput()) return JsonNode.of("null"); + try { + byte[] bytes = + fileResourceService.copyFileResourceContent( + fileResourceService.getFileResource(fileResourceId)); + return JsonNode.of(new String(bytes, StandardCharsets.UTF_8)); + } catch (IOException ex) { + log.warn("Could not copy file content to error info for file: " + fileResourceId, ex); + return JsonNode.of("\"" + ex.getMessage() + "\""); + } + } + + private static JsonNode errorWithMessage(JobType type, JsonNode error) { + String codeName = JsonMixed.of(error).getString("code").string(); + String template = + type == TRACKER_IMPORT_JOB + ? ValidationCode.valueOf(codeName).getMessage() + : ErrorCode.valueOf(codeName).getMessage(); + Object[] args = JsonMixed.of(error).getArray("args").stringValues().toArray(new String[0]); + String msg = MessageFormat.format(template, args); + return error.extract().addMembers(e -> e.addString("message", msg)); } @Override diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerLoopService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerLoopService.java index ceb9d77c38c2..e461105b5491 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerLoopService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerLoopService.java @@ -46,7 +46,6 @@ import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.commons.util.DebugUtils; import org.hisp.dhis.eventhook.EventHookPublisher; -import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.leader.election.LeaderManager; import org.hisp.dhis.message.MessageService; @@ -284,8 +283,7 @@ private void updateProgress(@Nonnull String jobId) { if (job == null) return; try { JobProgress.Progress progress = job.getProgress(); - String errorCodes = - progress.getErrorCodes().stream().map(ErrorCode::name).sorted().collect(joining(" ")); + String errorCodes = progress.getErrorCodes().stream().sorted().collect(joining(" ")); jobConfigurationStore.updateProgress( jobId, jsonMapper.writeValueAsString(progress), errorCodes); } catch (JsonProcessingException ex) { diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java index 6a66f2e6f657..fdcc7f41eae1 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/DefaultJobSchedulerService.java @@ -29,13 +29,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import java.text.MessageFormat; import java.util.*; import javax.annotation.Nonnull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.feedback.ConflictException; -import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.feedback.NotFoundException; import org.hisp.dhis.scheduling.JobProgress.Progress; import org.springframework.stereotype.Service; @@ -127,15 +125,11 @@ public List getErrors(@Nonnull String jobId) { if (json == null) return List.of(); Progress progress = mapToProgress("{\"sequence\":[],\"errors\":" + json + "}"); if (progress == null) return List.of(); - Map>> map = progress.getErrors(); + Map>> map = progress.getErrors(); if (map.isEmpty()) return List.of(); - List errors = - map.values().stream() - .flatMap(e -> e.values().stream().flatMap(Collection::stream)) - .toList(); - errors.forEach( - e -> e.setMessage(MessageFormat.format(e.getCode().getMessage(), e.getArgs().toArray()))); - return errors; + return map.values().stream() + .flatMap(e -> e.values().stream().flatMap(Collection::stream)) + .toList(); } @Override diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java index 3518285e8628..d75dc6817f85 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/HibernateJobConfigurationStore.java @@ -261,6 +261,7 @@ select jsonb_build_object( 'created', c.created, 'executed', c.lastexecuted, 'finished', c.lastfinished, + 'file', fr.uid, 'filesize', fr.contentlength, 'filetype', fr.contenttype, 'errors', c.progress -> 'errors') #>> '{}' diff --git a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java index f3367f15185a..f65df4e9af92 100644 --- a/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java +++ b/dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/scheduling/RecordingJobProgress.java @@ -42,6 +42,7 @@ import lombok.extern.slf4j.Slf4j; import org.hisp.dhis.feedback.ErrorCode; import org.hisp.dhis.message.MessageService; +import org.hisp.dhis.tracker.imports.validation.ValidationCode; import org.hisp.dhis.user.CurrentUserDetails; import org.hisp.dhis.user.CurrentUserUtil; @@ -150,6 +151,23 @@ public void addError( @CheckForNull String uid, @Nonnull String type, @Nonnull List args) { + addError(code.name(), uid, type, args); + } + + @Override + public void addError( + @Nonnull ValidationCode code, + @CheckForNull String uid, + @Nonnull String type, + @Nonnull List args) { + addError(code.name(), uid, type, args); + } + + private void addError( + @Nonnull String code, + @CheckForNull String uid, + @Nonnull String type, + @Nonnull List args) { try { // Note: we use empty string in case the UID is not known/defined yet to allow use in maps progress.addError(new Error(code, uid == null ? "" : uid, type, args)); diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/Error.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/Error.java index 4038def54b20..880bbf30ff93 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/Error.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/Error.java @@ -29,7 +29,11 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; import lombok.Builder; +import lombok.EqualsAndHashCode; import lombok.Value; import org.hisp.dhis.common.OpenApi; @@ -37,43 +41,24 @@ @Builder @OpenApi.Shared(name = "TrackerImportError") public class Error { - private final String errorMessage; - private final String errorCode; - - private final String trackerType; - - private final String uid; + @Nonnull @JsonProperty String message; + @Nonnull @JsonProperty String errorCode; + @Nonnull @JsonProperty String trackerType; + @Nonnull @JsonProperty String uid; + @EqualsAndHashCode.Exclude @Nonnull @JsonProperty List args; @JsonCreator public Error( - @JsonProperty("message") String errorMessage, - @JsonProperty("errorCode") String errorCode, - @JsonProperty("trackerType") String trackerType, - @JsonProperty("uid") String uid) { - this.errorMessage = errorMessage; + @Nonnull @JsonProperty("message") String message, + @Nonnull @JsonProperty("errorCode") String errorCode, + @Nonnull @JsonProperty("trackerType") String trackerType, + @Nonnull @JsonProperty("uid") String uid, + @CheckForNull @JsonProperty("args") List args) { + this.message = message; this.errorCode = errorCode; this.trackerType = trackerType; this.uid = uid; - } - - @JsonProperty - public String getErrorCode() { - return errorCode; - } - - @JsonProperty - public String getMessage() { - return errorMessage; - } - - @JsonProperty - public String getTrackerType() { - return trackerType; - } - - @JsonProperty - public String getUid() { - return uid; + this.args = args == null ? List.of() : args; } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/ValidationReport.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/ValidationReport.java index 6e32596d894e..d67f61a2b4ed 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/ValidationReport.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/report/ValidationReport.java @@ -75,10 +75,11 @@ private static List convertToError(List errors) { .map( e -> Error.builder() - .errorMessage(e.getMessage()) + .message(e.getMessage()) .errorCode(e.getCode()) .trackerType(e.getType()) .uid(e.getUid()) + .args(e.getArgs()) .build()) .collect(Collectors.toList()); } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Error.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Error.java index 58c2694653bf..a9857f1a9e4c 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Error.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Error.java @@ -27,18 +27,18 @@ */ package org.hisp.dhis.tracker.imports.validation; +import java.util.List; import lombok.Value; import org.hisp.dhis.tracker.TrackerType; @Value public class Error implements Validation { - String message; + String message; ValidationCode code; - TrackerType type; - String uid; + List args; public ValidationCode getErrorCode() { return code; @@ -67,4 +67,9 @@ public String getType() { public String getUid() { return uid; } + + @Override + public List getArgs() { + return args.stream().map(obj -> obj == null ? null : obj.toString()).toList(); + } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/PersistablesFilter.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/PersistablesFilter.java index e33bb5855277..867054cc842e 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/PersistablesFilter.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/PersistablesFilter.java @@ -321,15 +321,15 @@ private void addErrorsForChildren( } private static Error error(ValidationCode code, TrackerDto notPersistable, TrackerDto reason) { - String message = - MessageFormat.format( - code.getMessage(), - notPersistable.getTrackerType().getName(), - notPersistable.getUid(), - reason.getTrackerType().getName(), - reason.getUid()); - - return new Error(message, code, notPersistable.getTrackerType(), notPersistable.getUid()); + Object[] args = { + notPersistable.getTrackerType().getName(), + notPersistable.getUid(), + reason.getTrackerType().getName(), + reason.getUid() + }; + String message = MessageFormat.format(code.getMessage(), args); + return new Error( + message, code, notPersistable.getTrackerType(), notPersistable.getUid(), List.of(args)); } /** diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Reporter.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Reporter.java index 49648c5c2379..8588be7d67ed 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Reporter.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Reporter.java @@ -27,12 +27,7 @@ */ package org.hisp.dhis.tracker.imports.validation; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.function.BooleanSupplier; import java.util.function.Predicate; import lombok.AccessLevel; @@ -158,7 +153,8 @@ public boolean addError(TrackerDto dto, ValidationCode code, Object... args) { MessageFormatter.format(idSchemes, code.getMessage(), args), code, dto.getTrackerType(), - dto.getUid())); + dto.getUid(), + args == null ? List.of() : Arrays.asList(args))); return true; } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Validation.java b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Validation.java index f0a4a51c5de2..229de7adc478 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Validation.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/main/java/org/hisp/dhis/tracker/imports/validation/Validation.java @@ -27,6 +27,8 @@ */ package org.hisp.dhis.tracker.imports.validation; +import java.util.List; + /** * Validation represents an issue found by the validation process. It contains information that help * the client to understand and fix the problem. @@ -39,4 +41,8 @@ public interface Validation { String getType(); String getUid(); + + default List getArgs() { + return List.of(); + } } diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/report/TrackerBundleImportReportTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/report/TrackerBundleImportReportTest.java index 0ecabc5ed491..d2f5d2761e5c 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/report/TrackerBundleImportReportTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/report/TrackerBundleImportReportTest.java @@ -71,7 +71,7 @@ class TrackerBundleImportReportTest { @InjectMocks private DefaultTrackerImportService trackerImportService; - private ObjectMapper jsonMapper = JacksonObjectMapperConfig.staticJsonMapper(); + private final ObjectMapper jsonMapper = JacksonObjectMapperConfig.staticJsonMapper(); @Test void testImportReportErrors() { @@ -135,7 +135,8 @@ void testSerializingAndDeserializingImportReport() throws JsonProcessingExceptio "Could not find OrganisationUnit: ``, linked to Tracked Entity.", ValidationCode.E1049.name(), TRACKED_ENTITY.name(), - "BltTZV9HvEZ"))); + "BltTZV9HvEZ", + List.of("BltTZV9HvEZ")))); tvr.addWarnings( List.of( new Warning( @@ -198,8 +199,8 @@ void testSerializingAndDeserializingImportReport() throws JsonProcessingExceptio deserializedReportTrackerTypeReport.getStats()); // Verify Validation Report - Error Reports assertEquals( - toSerializeReport.getValidationReport().getErrors().get(0).getErrorMessage(), - deserializedReport.getValidationReport().getErrors().get(0).getErrorMessage()); + toSerializeReport.getValidationReport().getErrors().get(0).getMessage(), + deserializedReport.getValidationReport().getErrors().get(0).getMessage()); assertEquals( toSerializeReport.getValidationReport().getErrors().get(0).getErrorCode(), deserializedReport.getValidationReport().getErrors().get(0).getErrorCode()); @@ -245,7 +246,8 @@ private ValidationReport createValidationReport() { "Could not find OrganisationUnit: ``, linked to Tracked Entity.", ValidationCode.E1049.name(), TRACKED_ENTITY.name(), - "BltTZV9HvEZ")), + "BltTZV9HvEZ", + List.of("BltTZV9HvEZ"))), List.of( new Warning( "ProgramStage `l8oDIfJJhtg` does not allow user assignment", diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ReporterTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ReporterTest.java index b6cb4acb7b99..f10e22052b98 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ReporterTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ReporterTest.java @@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; import org.hisp.dhis.tracker.TrackerType; import org.hisp.dhis.tracker.imports.TrackerIdSchemeParams; import org.junit.jupiter.api.Test; @@ -75,7 +76,8 @@ void hasWarningReportNotFound() { } private Error eventError() { - return new Error("some error", ValidationCode.E1000, TrackerType.EVENT, "JgDfHAGzzfS"); + return new Error( + "some error", ValidationCode.E1000, TrackerType.EVENT, "JgDfHAGzzfS", List.of()); } private Warning eventWarning() { diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ValidationResultTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ValidationResultTest.java index e714a0ee5c4e..ffddf319a64f 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ValidationResultTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/ValidationResultTest.java @@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; import java.util.Set; import org.hisp.dhis.common.CodeGenerator; import org.hisp.dhis.tracker.TrackerType; @@ -77,7 +78,7 @@ private Error newError(ValidationCode code) { } private Error newError(String uid, ValidationCode code) { - return new Error("", code, TrackerType.EVENT, uid); + return new Error("", code, TrackerType.EVENT, uid, List.of()); } private Warning newWarning() { diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/AllTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/AllTest.java index b463fac888c3..b70f34ee3be4 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/AllTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/AllTest.java @@ -148,7 +148,8 @@ public boolean needsToRun(TrackerImportStrategy strategy) { * tracker type, uid or error code. */ private static void addError(Reporter reporter, String message) { - reporter.addError(new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid")); + reporter.addError( + new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid", List.of())); } private List actualErrorMessages() { diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/EachTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/EachTest.java index 3930ca6298ee..70e746965bdf 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/EachTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/EachTest.java @@ -151,7 +151,8 @@ private static Enrollment enrollment(String uid, String... notes) { * tracker type, uid or error code. */ private static void addError(Reporter reporter, String message) { - reporter.addError(new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid")); + reporter.addError( + new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid", List.of())); } private List actualErrorMessages() { diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/FieldTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/FieldTest.java index e2dc21d45980..64ce221f2287 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/FieldTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/FieldTest.java @@ -74,7 +74,7 @@ void testFieldWithValidator() { Validator isValidUid = (r, b, uid) -> { // to demonstrate that we are getting the trackedEntity field - r.addError(new Error(uid, E1000, ENROLLMENT, uid)); + r.addError(new Error(uid, E1000, ENROLLMENT, uid, List.of(uid))); }; Validator validator = field(Enrollment::getTrackedEntity, isValidUid); @@ -172,7 +172,8 @@ void testFieldWithPredicateSucceeding() { * tracker type, uid or error code. */ private static void addError(Reporter reporter, String message) { - reporter.addError(new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid")); + reporter.addError( + new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid", List.of())); } private List actualErrorMessages() { diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/SeqTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/SeqTest.java index 207b09c860f1..21e3a14955ed 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/SeqTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/SeqTest.java @@ -243,7 +243,8 @@ public void validate(Reporter reporter, TrackerBundle bundle, String input) { * tracker type, uid or error code. */ private static void addError(Reporter reporter, String message) { - reporter.addError(new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid")); + reporter.addError( + new Error(message, ValidationCode.E9999, TrackerType.TRACKED_ENTITY, "uid", List.of())); } /** diff --git a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/RepeatedEventsValidatorTest.java b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/RepeatedEventsValidatorTest.java index 338d55164001..4d946674c41a 100644 --- a/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/RepeatedEventsValidatorTest.java +++ b/dhis-2/dhis-services/dhis-service-tracker/src/test/java/org/hisp/dhis/tracker/imports/validation/validator/event/RepeatedEventsValidatorTest.java @@ -191,7 +191,8 @@ void testTwoEventsInNotRepeatableProgramStageWhenOneIsInvalidArePassingValidatio List events = Lists.newArrayList(invalidEvent, notRepeatableEvent("B")); bundle.setEvents(events); events.forEach(e -> bundle.setStrategy(e, TrackerImportStrategy.CREATE_AND_UPDATE)); - reporter.addError(new Error("", E9999, invalidEvent.getTrackerType(), invalidEvent.getUid())); + reporter.addError( + new Error("", E9999, invalidEvent.getTrackerType(), invalidEvent.getUid(), List.of())); validator.validate(reporter, bundle, bundle.getEvents()); diff --git a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobConfigurationRunErrorsControllerTest.java b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobConfigurationRunErrorsControllerTest.java index 0a4971250222..4c4efb2e14d3 100644 --- a/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobConfigurationRunErrorsControllerTest.java +++ b/dhis-2/dhis-test-web-api/src/test/java/org/hisp/dhis/webapi/controller/JobConfigurationRunErrorsControllerTest.java @@ -116,19 +116,55 @@ void testGetJobRunErrors_ObjectProgressErrors() { assertEquals(1, errors.size()); } + @Test + void testGetJobRunErrors_ListIncludeInput() throws InterruptedException { + // language=JSON + String json = + """ + { + "trackedEntities": [ + { + "trackedEntity":"sHH8mh1Fn0z", + "trackedEntityType": "nEenWmSyUEp", + "orgUnit": "DiszpKrYNg7" + } + ] + } + """; + JsonWebMessage msg = + POST("/tracker?async=true", json).content(HttpStatus.OK).as(JsonWebMessage.class); + String jobId = msg.getString("response.id").string(); + waitUntilJobIsComplete(jobId); + + JsonArray errors = GET("/jobConfigurations/errors?includeInput=true").content(); + assertEquals(2, errors.size()); + JsonObject trackerImportError = + errors.asList(JsonObject.class).stream() + .filter(obj -> obj.getString("id").string().equals(jobId)) + .findFirst() + .orElseThrow(); + + // language=JSON + String expected = + """ + {"trackedEntities":[{"trackedEntity":"sHH8mh1Fn0z","trackedEntityType":{"idScheme":"UID","identifier":"nEenWmSyUEp"},"orgUnit":{"idScheme":"UID","identifier":"DiszpKrYNg7"},"inactive":false,"deleted":false,"potentialDuplicate":false,"relationships":[],"attributes":[],"enrollments":[]}],"enrollments":[],"events":[],"relationships":[]}"""; + assertEquals(expected, trackerImportError.getObject("input").node().getDeclaration()); + } + private String createAndRunImportWithErrors() throws InterruptedException { - JsonWebMessage message = - POST( - "/metadata?async=true", - "{'organisationUnits':[{'name':'My Unit', 'shortName':'OU1'}]}") - .content(HttpStatus.OK) - .as(JsonWebMessage.class); - String jobId = message.getString("response.id").string(); + String json = "{'organisationUnits':[{'name':'My Unit', 'shortName':'OU1'}]}"; + JsonWebMessage msg = + POST("/metadata?async=true", json).content(HttpStatus.OK).as(JsonWebMessage.class); + String jobId = msg.getString("response.id").string(); + waitUntilJobIsComplete(jobId); + return jobId; + } + + private void waitUntilJobIsComplete(String jobId) throws InterruptedException { BooleanSupplier jobCompleted = () -> isDone(GET("/jobConfigurations/{id}/gist?fields=id,jobStatus", jobId).content()); assertTrue(await(ofSeconds(10), jobCompleted), "import did not run"); - return jobId; } private static boolean isDone(JsonMixed config) { diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportJob.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportJob.java index 4af6ddd09ca5..1eeb25641f41 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportJob.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/metadata/MetadataImportJob.java @@ -103,12 +103,12 @@ public void execute(JobConfiguration config, JobProgress progress) { if (report.hasErrorReports()) { report.forEachErrorReport( - r -> + e -> progress.addError( - r.getErrorCode(), - r.getMainId(), - r.getMainKlass().getSimpleName(), - r.getArgs())); + e.getErrorCode(), + e.getMainId(), + e.getMainKlass().getSimpleName(), + e.getArgs())); } notifier.addJobSummary(config, report, ImportReport.class); diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java index 11aae6ce13d6..6e4d4336f014 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/scheduling/JobConfigurationController.java @@ -71,6 +71,7 @@ public class JobConfigurationController extends AbstractCrudController getJobRunErrors(JobRunErrorsParams params) { return jobConfigurationService.findJobRunErrors(params); @@ -78,16 +79,13 @@ public List getJobRunErrors(JobRunErrorsParams params) { @GetMapping("{uid}/errors") public JsonObject getJobRunErrors( - @PathVariable("uid") @OpenApi.Param({UID.class, JobConfiguration.class}) UID uid) - throws NotFoundException { + @PathVariable("uid") @OpenApi.Param({UID.class, JobConfiguration.class}) UID uid, + @CurrentUser User currentUser) + throws NotFoundException, ForbiddenException { + checkExecutingUserOrAdmin(uid, currentUser); List errors = jobConfigurationService.findJobRunErrors(new JobRunErrorsParams().setJob(uid)); - if (errors.isEmpty()) { - JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); - if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); - return JsonMixed.of("{}"); - } - return errors.get(0); + return errors.isEmpty() ? JsonMixed.of("{}") : errors.get(0); } @GetMapping("/due") @@ -128,25 +126,19 @@ public ObjectReport executeNow(@PathVariable("uid") String uid) @PostMapping("{uid}/cancel") @ResponseStatus(HttpStatus.NO_CONTENT) - public void cancelExecution(@PathVariable("uid") String uid, @CurrentUser User currentUser) + public void cancelExecution(@PathVariable("uid") UID uid, @CurrentUser User currentUser) throws NotFoundException, ForbiddenException { - JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid); - if (obj == null) throw new NotFoundException(JobConfiguration.class, uid); - boolean canCancel = - currentUser.isSuper() - || currentUser.isAuthorized("F_PERFORM_MAINTENANCE") - || currentUser.getUid().equals(obj.getExecutedBy()); - if (!canCancel) throw new ForbiddenException(JobConfiguration.class, obj.getUid()); - jobSchedulerService.requestCancel(uid); + checkExecutingUserOrAdmin(uid, currentUser); + jobSchedulerService.requestCancel(uid.getValue()); } - @PreAuthorize("hasRole('ALL') or hasRole('F_PERFORM_MAINTENANCE')") @GetMapping("{uid}/progress") - public Progress getProgress(@PathVariable("uid") String uid) { - return jobSchedulerService.getProgress(uid); + public Progress getProgress(@PathVariable("uid") UID uid, @CurrentUser User currentUser) + throws ForbiddenException, NotFoundException { + checkExecutingUserOrAdmin(uid, currentUser); + return jobSchedulerService.getProgress(uid.getValue()); } - @PreAuthorize("hasRole('ALL') or hasRole('F_PERFORM_MAINTENANCE')") @GetMapping("{uid}/progress/errors") public List getErrors(@PathVariable("uid") String uid) { return jobSchedulerService.getErrors(uid); @@ -161,9 +153,9 @@ public void deleteDoneJobs(@RequestParam int minutes) { @PostMapping("{uid}/enable") @ResponseStatus(HttpStatus.NO_CONTENT) - public void enable(@PathVariable("uid") String uid) throws NotFoundException, ConflictException { - JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid); - if (obj == null) throw new NotFoundException(JobConfiguration.class, uid); + public void enable(@PathVariable("uid") UID uid) throws NotFoundException, ConflictException { + JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); + if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); checkModifiable(obj, "Job %s is a system job that cannot be modified."); if (!obj.isEnabled()) { obj.setEnabled(true); @@ -173,9 +165,9 @@ public void enable(@PathVariable("uid") String uid) throws NotFoundException, Co @PostMapping("{uid}/disable") @ResponseStatus(HttpStatus.NO_CONTENT) - public void disable(@PathVariable("uid") String uid) throws NotFoundException, ConflictException { - JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid); - if (obj == null) throw new NotFoundException(JobConfiguration.class, uid); + public void disable(@PathVariable("uid") UID uid) throws NotFoundException, ConflictException { + JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); + if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); checkModifiable(obj, "Job %s is a system job that cannot be modified."); if (obj.isEnabled()) { obj.setEnabled(false); @@ -216,4 +208,15 @@ private void checkModifiable(JobConfiguration configuration, String message) throw new ConflictException(String.format(message, identifier)); } } + + private void checkExecutingUserOrAdmin(UID uid, User currentUser) + throws NotFoundException, ForbiddenException { + JobConfiguration obj = jobConfigurationService.getJobConfigurationByUid(uid.getValue()); + if (obj == null) throw new NotFoundException(JobConfiguration.class, uid.getValue()); + boolean canCancel = + currentUser.isSuper() + || currentUser.isAuthorized("F_PERFORM_MAINTENANCE") + || currentUser.getUid().equals(obj.getExecutedBy()); + if (!canCancel) throw new ForbiddenException(JobConfiguration.class, obj.getUid()); + } } diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportController.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportController.java index e882355a4df9..143578aacd63 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportController.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportController.java @@ -32,11 +32,8 @@ import static org.hisp.dhis.webapi.utils.ContextUtils.setNoStore; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectOutputStream; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.*; import java.util.Deque; import java.util.List; import java.util.Optional; @@ -102,6 +99,8 @@ public class TrackerImportController { private final JobConfigurationService jobConfigurationService; + private final ObjectMapper jsonMapper; + @PostMapping(value = "", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) @ResponseBody public WebMessage asyncPostJsonTracker( @@ -133,17 +132,11 @@ private WebMessage startAsyncTracker( JobConfiguration config = new JobConfiguration(JobType.TRACKER_IMPORT_JOB); config.setExecutedBy(user.getUid()); config.setJobParameters(params); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - - oos.writeObject(trackerObjects); - - oos.flush(); - oos.close(); - InputStream is = new ByteArrayInputStream(baos.toByteArray()); + byte[] jsonInput = jsonMapper.writeValueAsBytes(trackerObjects); - jobSchedulerService.executeNow(jobConfigurationService.create(config, contentType, is)); + jobSchedulerService.executeNow( + jobConfigurationService.create(config, contentType, new ByteArrayInputStream(jsonInput))); String jobId = config.getUid(); String location = ContextUtils.getRootPath(request) + "/tracker/jobs/" + jobId; return ok(TRACKER_JOB_ADDED) diff --git a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportJob.java b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportJob.java index d144c60e0970..2969adee5894 100644 --- a/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportJob.java +++ b/dhis-2/dhis-web-api/src/main/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportJob.java @@ -27,9 +27,9 @@ */ package org.hisp.dhis.webapi.controller.tracker.imports; +import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; -import java.io.ObjectInputStream; import java.util.function.Consumer; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -46,6 +46,7 @@ import org.hisp.dhis.tracker.imports.report.ImportReport; import org.hisp.dhis.tracker.imports.report.Stats; import org.hisp.dhis.tracker.imports.report.Status; +import org.hisp.dhis.tracker.imports.validation.ValidationCode; import org.springframework.stereotype.Component; @Slf4j @@ -55,6 +56,7 @@ public class TrackerImportJob implements Job { private final TrackerImportService trackerImportService; private final FileResourceService fileResourceService; private final Notifier notifier; + private final ObjectMapper jsonMapper; @Override public JobType getJobType() { @@ -78,6 +80,20 @@ public void execute(JobConfiguration config, JobProgress progress) { return; } notifier.addJobSummary(config, report, ImportReport.class); + + if (report.getValidationReport().hasErrors()) { + report + .getValidationReport() + .getErrors() + .forEach( + e -> + progress.addError( + ValidationCode.valueOf(e.getErrorCode()), + e.getUid(), + e.getTrackerType(), + e.getArgs())); + } + Stats stats = report.getStats(); Consumer endProcess = report.getStatus() == Status.ERROR ? progress::failedProcess : progress::completedProcess; @@ -94,9 +110,7 @@ public void execute(JobConfiguration config, JobProgress progress) { } } - private TrackerObjects toTrackerObjects(InputStream input) - throws IOException, ClassNotFoundException { - ObjectInputStream ois = new ObjectInputStream(input); - return (TrackerObjects) ois.readObject(); + private TrackerObjects toTrackerObjects(InputStream input) throws IOException { + return jsonMapper.readValue(input, TrackerObjects.class); } } diff --git a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportControllerTest.java b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportControllerTest.java index 67610dbe6e05..b0855f0121cb 100644 --- a/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportControllerTest.java +++ b/dhis-2/dhis-web-api/src/test/java/org/hisp/dhis/webapi/controller/tracker/imports/TrackerImportControllerTest.java @@ -44,6 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.HashMap; import java.util.LinkedList; import org.hisp.dhis.common.CodeGenerator; @@ -111,7 +112,8 @@ public void setUp() { csvEventService, notifier, jobSchedulerService, - jobConfigurationService); + jobConfigurationService, + new ObjectMapper()); mockMvc = MockMvcBuilders.standaloneSetup(controller)