All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.exactpro.sf.services.json.JSONVisitorUtility Maven / Gradle / Ivy
/******************************************************************************
* Copyright 2009-2021 Exactpro (Exactpro Systems Limited)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.exactpro.sf.services.json;
import static com.exactpro.sf.common.messages.structures.StructureUtils.getAttributeValue;
import static com.exactpro.sf.services.json.JSONMessageHelper.FROM_ARRAY_ATTR;
import static com.exactpro.sf.services.json.JSONMessageHelper.IS_SIMPLE_ROOT_VALUE_ATTR;
import static com.exactpro.sf.services.json.JSONMessageHelper.IS_URI_PARAM_ATTR;
import static com.exactpro.sf.services.json.JSONMessageHelper.IS_STUB_FIELD_ATTR;
import static com.google.common.collect.Iterables.get;
import static java.lang.String.format;
import static java.lang.System.lineSeparator;
import static org.apache.commons.lang3.BooleanUtils.toBoolean;
import static org.apache.commons.lang3.StringUtils.defaultString;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.commons.lang3.ObjectUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.exactpro.sf.common.messages.IMessage;
import com.exactpro.sf.common.messages.MsgMetaData;
import com.exactpro.sf.common.messages.structures.IFieldStructure;
import com.exactpro.sf.common.messages.structures.StructureUtils;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
public class JSONVisitorUtility {
public static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
.optionalEnd()
.append(DateTimeFormatter.ofPattern("'Z'"))
.toFormatter().withZone(ZoneOffset.UTC);
public static final String FORMAT_ATTRIBUTE = "format";
public static final String ISO_UTC_FORMAT = "ISO_UTC";
public static final String ATTRIBUTE_FIELD_NAME = "FieldName";
public static String getJsonFieldName(IFieldStructure fldStruct) {
String jsonFieldName = getAttributeValue(fldStruct, ATTRIBUTE_FIELD_NAME);
return ObjectUtils.defaultIfNull(jsonFieldName, fldStruct.getName());
}
@Nullable
public static String checkForUnexpectedFields(@NotNull TreeNode node, @NotNull IFieldStructure structure) {
Collection expectedFields = structure.getFields().values().stream()
.map(JSONVisitorUtility::getJsonFieldName)
.collect(Collectors.toSet());
Collection unexpectedFields = new HashSet<>();
node.fieldNames().forEachRemaining(fieldName -> {
if (!expectedFields.contains(fieldName)) {
unexpectedFields.add(fieldName);
}
});
return unexpectedFields.isEmpty() ? null : format("Unexpected fields in message '%s': %s", structure.getName(), unexpectedFields);
}
@SuppressWarnings("IfMayBeConditional")
public static void addRejectReason(@NotNull IMessage message, String reason) {
MsgMetaData metaData = message.getMetaData();
String oldReason = metaData.getRejectReason();
if (oldReason != null && reason != null) {
metaData.setRejectReason(oldReason + lineSeparator() + reason);
} else {
metaData.setRejectReason(defaultString(oldReason, reason));
}
}
@NotNull
public static JsonNode preprocessMessageNode(@NotNull JsonNode node, @NotNull IFieldStructure structure) {
boolean fromArray = toBoolean(StructureUtils.getAttributeValue(structure, FROM_ARRAY_ATTR));
boolean simpleRoot = toBoolean(StructureUtils.getAttributeValue(structure, IS_SIMPLE_ROOT_VALUE_ATTR));
if (!fromArray) {
return simpleRoot ? transformSimpleRoot(node, structure) : node;
}
if (!node.isArray()) {
throw new IllegalArgumentException("Node is not an array node: " + structure.getName());
}
Set fieldNames = structure.getFields().keySet();
Map fields = new LinkedHashMap<>();
int fieldCount = Math.max(node.size(), fieldNames.size());
for (int i = 0; i < fieldCount; i++) {
JsonNode fieldValue = node.get(i);
if (fieldValue == null) {
break;
}
String fieldName = get(fieldNames, i, "Field" + i);
fields.put(fieldName, fieldValue);
}
return new ObjectNode(JsonNodeFactory.instance, fields);
}
@NotNull
public static List convertToKeyValueList(String structureName, JsonNode node) {
if (!node.isObject()) {
throw new IllegalArgumentException("The node is not an object: " + structureName);
}
List jsonNodes = new ArrayList<>();
Iterator> fields = node.fields();
while (fields.hasNext()) {
Entry entry = fields.next();
Map newFields = new HashMap<>();
newFields.put("key", new TextNode(entry.getKey()));
newFields.put("value", entry.getValue());
jsonNodes.add(new ObjectNode(JsonNodeFactory.instance, newFields));
}
return jsonNodes;
}
public static TextNode convertCharToTextNode(Character v) {
if (v == null) {
return null;
}
return new TextNode(v.toString());
}
public static boolean isWritable(@NotNull IFieldStructure structure) {
return !toBoolean(StructureUtils.getAttributeValue(structure, IS_URI_PARAM_ATTR))
&& !toBoolean(StructureUtils.getAttributeValue(structure, IS_STUB_FIELD_ATTR));
}
@NotNull
public static JsonNode extractSimpleRoot(JsonNode node, IFieldStructure structure) {
String valueFieldName = getValueFieldName(structure);
return Objects.requireNonNull(node.get(valueFieldName), () -> "Original node " + node.getNodeType() + " does not contain the field " + valueFieldName);
}
@NotNull
private static JsonNode transformSimpleRoot(@NotNull JsonNode node, @NotNull IFieldStructure structure) {
String valueFieldName = getValueFieldName(structure);
return new ObjectNode(JsonNodeFactory.instance, Collections.singletonMap(valueFieldName, node));
}
private static String getValueFieldName(@NotNull IFieldStructure structure) {
List valueFields = structure.getFields().values().stream()
.filter(JSONVisitorUtility::isWritable)
.collect(Collectors.toList());
if (valueFields.size() != 1) {
throw new IllegalArgumentException(format("Structure %s has %d writable fields instead of 1", structure.getName(), valueFields.size()));
}
String valueFieldName = valueFields.get(0).getName();
return valueFieldName;
}
}