com.datadog.api.client.JSON Maven / Gradle / Ivy
/*
* Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
* This product includes software developed at Datadog (https://www.datadoghq.com/).
* Copyright 2019-Present Datadog, Inc.
*/
package com.datadog.api.client;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import jakarta.ws.rs.core.GenericType;
import jakarta.ws.rs.ext.ContextResolver;
import java.text.DateFormat;
import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.openapitools.jackson.nullable.JsonNullableModule;
@jakarta.annotation.Generated(
value = "https://github.com/DataDog/datadog-api-client-java/blob/master/.generator")
public class JSON implements ContextResolver {
private ObjectMapper mapper;
public JSON() {
mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.configure(MapperFeature.ALLOW_COERCION_OF_SCALARS, false);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, true);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
mapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
mapper.enable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);
mapper.setDateFormat(new RFC3339DateFormat());
mapper.registerModule(new JavaTimeModule());
SimpleModule module = new SimpleModule();
module.addSerializer(OffsetDateTime.class, new JsonTimeSerializer());
mapper.registerModule(module);
JsonNullableModule jnm = new JsonNullableModule();
mapper.registerModule(jnm);
}
/**
* Set the date format for JSON (de)serialization with Date properties.
*
* @param dateFormat Date format
*/
public void setDateFormat(DateFormat dateFormat) {
mapper.setDateFormat(dateFormat);
}
@Override
public ObjectMapper getContext(Class> type) {
return mapper;
}
/**
* Get the object mapper
*
* @return object mapper
*/
public ObjectMapper getMapper() {
return mapper;
}
/**
* Returns the target model class that should be used to deserialize the input data. The
* discriminator mappings are used to determine the target model class.
*
* @param node The input data.
* @param modelClass The class that contains the discriminator mappings.
* @return The matching class
*/
public static Class> getClassForElement(JsonNode node, Class> modelClass) {
ClassDiscriminatorMapping cdm = modelDiscriminators.get(modelClass);
if (cdm != null) {
return cdm.getClassForElement(node, new HashSet>());
}
return null;
}
/** Helper class to register the discriminator mappings. */
private static class ClassDiscriminatorMapping {
// The model class name.
Class> modelClass;
// The name of the discriminator property.
String discriminatorName;
// The discriminator mappings for a model class.
Map> discriminatorMappings;
// Constructs a new class discriminator.
ClassDiscriminatorMapping(Class> cls, String propertyName, Map> mappings) {
modelClass = cls;
discriminatorName = propertyName;
discriminatorMappings = new HashMap>();
if (mappings != null) {
discriminatorMappings.putAll(mappings);
}
}
// Return the name of the discriminator property for this model class.
String getDiscriminatorPropertyName() {
return discriminatorName;
}
// Return the discriminator value or null if the discriminator is not
// present in the payload.
String getDiscriminatorValue(JsonNode node) {
// Determine the value of the discriminator property in the input data.
if (discriminatorName != null) {
// Get the value of the discriminator property, if present in the input payload.
node = node.get(discriminatorName);
if (node != null && node.isValueNode()) {
String discrValue = node.asText();
if (discrValue != null) {
return discrValue;
}
}
}
return null;
}
/**
* Returns the target model class that should be used to deserialize the input data. This
* function can be invoked for anyOf/oneOf composed models with discriminator mappings. The
* discriminator mappings are used to determine the target model class.
*
* @param node The input data.
* @param visitedClasses The set of classes that have already been visited.
* @return The target class
*/
Class> getClassForElement(JsonNode node, Set> visitedClasses) {
if (visitedClasses.contains(modelClass)) {
// Class has already been visited.
return null;
}
// Determine the value of the discriminator property in the input data.
String discrValue = getDiscriminatorValue(node);
if (discrValue == null) {
return null;
}
Class> cls = discriminatorMappings.get(discrValue);
// It may not be sufficient to return this cls directly because that target class
// may itself be a composed schema, possibly with its own discriminator.
visitedClasses.add(modelClass);
for (Class> childClass : discriminatorMappings.values()) {
ClassDiscriminatorMapping childCdm = modelDiscriminators.get(childClass);
if (childCdm == null) {
continue;
}
if (!discriminatorName.equals(childCdm.discriminatorName)) {
discrValue = getDiscriminatorValue(node);
if (discrValue == null) {
continue;
}
}
if (childCdm != null) {
// Recursively traverse the discriminator mappings.
Class> childDiscr = childCdm.getClassForElement(node, visitedClasses);
if (childDiscr != null) {
return childDiscr;
}
}
}
return cls;
}
}
/**
* Returns true if inst is an instance of modelClass in the OpenAPI model hierarchy.
*
* The Java class hierarchy is not implemented the same way as the OpenAPI model hierarchy, so
* it's not possible to use the instanceof keyword.
*
* @param modelClass A OpenAPI model class.
* @param inst The instance object.
* @param visitedClasses Keep track of the hierarchy to break cycles
* @return Boolean indicating if the class matches
*/
public static boolean isInstanceOf(
Class> modelClass, Object inst, Set> visitedClasses) {
if (modelClass.isInstance(inst)) {
// This handles the 'allOf' use case with single parent inheritance.
return true;
}
if (visitedClasses.contains(modelClass)) {
// This is to prevent infinite recursion when the composed schemas have
// a circular dependency.
return false;
}
visitedClasses.add(modelClass);
// Traverse the oneOf/anyOf composed schemas.
Map descendants = modelDescendants.get(modelClass);
if (descendants != null) {
for (GenericType childType : descendants.values()) {
if (isInstanceOf(childType.getRawType(), inst, visitedClasses)) {
return true;
}
}
}
return false;
}
/** A map of discriminators for all model classes. */
private static Map, ClassDiscriminatorMapping> modelDiscriminators =
new HashMap, ClassDiscriminatorMapping>();
/** A map of oneOf/anyOf descendants for each model class. */
private static Map, Map> modelDescendants =
new HashMap, Map>();
/**
* Register a model class discriminator.
*
* @param modelClass the model class
* @param discriminatorPropertyName the name of the discriminator property
* @param mappings a map with the discriminator mappings.
*/
public static void registerDiscriminator(
Class> modelClass, String discriminatorPropertyName, Map> mappings) {
ClassDiscriminatorMapping m =
new ClassDiscriminatorMapping(modelClass, discriminatorPropertyName, mappings);
modelDiscriminators.put(modelClass, m);
}
/**
* Register the oneOf/anyOf descendants of the modelClass.
*
* @param modelClass the model class
* @param descendants a map of oneOf/anyOf descendants.
*/
public static void registerDescendants(
Class> modelClass, Map descendants) {
modelDescendants.put(modelClass, descendants);
}
private static JSON json;
static {
json = new JSON();
}
/**
* Get the default JSON instance.
*
* @return the default JSON instance
*/
public static JSON getDefault() {
return json;
}
/**
* Set the default JSON instance.
*
* @param json JSON instance to be used
*/
public static void setDefault(JSON json) {
JSON.json = json;
}
}