MarginCalculationResultDeserializer.java
/**
* Copyright (c) 2025, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.dynawo.margincalculation.json;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.powsybl.commons.json.JsonUtil;
import com.powsybl.dynawo.contingency.results.FailedCriterion;
import com.powsybl.dynawo.contingency.results.ScenarioResult;
import com.powsybl.dynawo.contingency.results.Status;
import com.powsybl.dynawo.margincalculation.results.LoadIncreaseResult;
import com.powsybl.dynawo.margincalculation.results.MarginCalculationResult;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author Laurent Issertial {@literal <laurent.issertial at rte-france.com>}
*/
public class MarginCalculationResultDeserializer extends StdDeserializer<MarginCalculationResult> {
MarginCalculationResultDeserializer() {
super(MarginCalculationResult.class);
}
public static MarginCalculationResult read(InputStream is) throws IOException {
Objects.requireNonNull(is);
ObjectMapper objectMapper = JsonUtil.createObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(MarginCalculationResult.class, new MarginCalculationResultDeserializer());
objectMapper.registerModule(module);
return objectMapper.readValue(is, MarginCalculationResult.class);
}
public static MarginCalculationResult read(Path jsonFile) {
Objects.requireNonNull(jsonFile);
try (InputStream is = Files.newInputStream(jsonFile)) {
return read(is);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public MarginCalculationResult deserialize(JsonParser parser, DeserializationContext ctx) throws IOException {
List<LoadIncreaseResult> loadIncreaseResults = new ArrayList<>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
switch (parser.currentName()) {
case "version" -> parser.nextToken(); // skip
case "loadIncreases" -> {
parser.nextToken();
deserializeLoadIncreaseResults(parser, loadIncreaseResults);
}
default -> throw getUnexpectedFieldException(parser);
}
}
return new MarginCalculationResult(loadIncreaseResults);
}
private void deserializeLoadIncreaseResults(JsonParser parser, List<LoadIncreaseResult> loadIncreaseResults) throws IOException {
while (parser.nextToken() != JsonToken.END_ARRAY) {
double loadLevel = 0;
Status status = null;
List<FailedCriterion> failedCriteria = new ArrayList<>();
List<ScenarioResult> scenarioResults = new ArrayList<>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
switch (parser.currentName()) {
case "loadLevel" -> loadLevel = parser.getValueAsDouble();
case "status" -> {
parser.nextToken();
status = parser.readValueAs(Status.class);
}
case "failedCriteria" -> {
parser.nextToken();
deserializeFailedCriteria(parser, failedCriteria);
}
case "scenarioResults" -> {
parser.nextToken();
deserializeScenarioResults(parser, scenarioResults);
}
default -> throw getUnexpectedFieldException(parser);
}
}
loadIncreaseResults.add(new LoadIncreaseResult(loadLevel, status, scenarioResults, failedCriteria));
}
}
private void deserializeFailedCriteria(JsonParser parser, List<FailedCriterion> failedCriteria) throws IOException {
while (parser.nextToken() != JsonToken.END_ARRAY) {
String description = null;
double time = 0;
while (parser.nextToken() != JsonToken.END_OBJECT) {
switch (parser.currentName()) {
case "description" -> description = parser.getValueAsString();
case "time" -> time = parser.getValueAsDouble();
default -> throw getUnexpectedFieldException(parser);
}
}
failedCriteria.add(new FailedCriterion(description, time));
}
}
private void deserializeScenarioResults(JsonParser parser, List<ScenarioResult> scenarioResults) throws IOException {
while (parser.nextToken() != JsonToken.END_ARRAY) {
String id = null;
Status status = null;
List<FailedCriterion> failedCriteria = new ArrayList<>();
while (parser.nextToken() != JsonToken.END_OBJECT) {
switch (parser.currentName()) {
case "id" -> id = parser.getValueAsString();
case "status" -> {
parser.nextToken();
status = parser.readValueAs(Status.class);
}
case "failedCriteria" -> {
parser.nextToken();
deserializeFailedCriteria(parser, failedCriteria);
}
default -> throw getUnexpectedFieldException(parser);
}
}
scenarioResults.add(new ScenarioResult(id, status, failedCriteria));
}
}
private static IllegalStateException getUnexpectedFieldException(JsonParser parser) throws IOException {
return new IllegalStateException("Unexpected field: " + parser.currentName());
}
}