All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.nike.backstopper.model.util.JsonUtilWithDefaultErrorContractDTOSupport Maven / Gradle / Ivy

package com.nike.backstopper.model.util;

import com.nike.backstopper.model.DefaultErrorDTO;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.cfg.SerializerFactoryConfig;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.BeanSerializerFactory;
import com.fasterxml.jackson.databind.ser.SerializerFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.UUID;

/**
 * Maps any Object to a JSON representation. The default {@link #writeValueAsString(Object)} method knows about
 * {@link DefaultErrorDTO} objects and will exclude empty {@link DefaultErrorDTO#metadata} maps from the serialized
 * output, and serialize {@link DefaultErrorDTO#code} as a JSON number rather than string when possible. It uses
 * {@link #DEFAULT_SMART_MAPPER} to do the serialization.
 *
 * 

If you want to always output the metadata object and/or always output error codes as strings you can generate the * appropriate serializer by calling {@link #generateErrorContractObjectMapper(boolean, boolean)} and passing in * whatever arguments you need, then use that by calling {@link #writeValueAsString(Object, ObjectMapper)} and pass in * your custom serializer. * *

You can further define a default generic error response that will be returned if there's a problem during * serialization by calling {@link #writeValueAsString(Object, ObjectMapper, String)}. The other methods use * {@link #DEFAULT_ERROR_RESPONSE_STRING} as a default. *

* Created by dsand7 on 9/25/14. */ @SuppressWarnings("WeakerAccess") public class JsonUtilWithDefaultErrorContractDTOSupport { private JsonUtilWithDefaultErrorContractDTOSupport() { // Do nothing } private static final Logger logger = LoggerFactory.getLogger(JsonUtilWithDefaultErrorContractDTOSupport.class); public static final ObjectMapper DEFAULT_SMART_MAPPER = generateErrorContractObjectMapper(true, true); public static final String DEFAULT_ERROR_RESPONSE_STRING = "{\"error_id\":\"%uuid%\",\"errors\":[{\"code\":10,\"message\":\"An error occurred while fulfilling the request\"}]}"; public static String writeValueAsString(Object value) { return writeValueAsString(value, DEFAULT_SMART_MAPPER); } public static String writeValueAsString(Object value, ObjectMapper mapper) { return writeValueAsString(value, mapper, DEFAULT_ERROR_RESPONSE_STRING); } public static String writeValueAsString(Object value, ObjectMapper mapper, String defaultResponseIfErrorDuringSerialization) { try { return mapper.writeValueAsString(value); } catch (Exception e) { String errorId = UUID.randomUUID().toString(); logger.error("Exception occurred while generating error code JSON. Falling back to default response with " + "error_id={}", errorId, e); if (defaultResponseIfErrorDuringSerialization == null) { defaultResponseIfErrorDuringSerialization = DEFAULT_ERROR_RESPONSE_STRING; } return defaultResponseIfErrorDuringSerialization.replace("%uuid%", errorId); } } public static ObjectMapper generateErrorContractObjectMapper(boolean excludeEmptyMetadataFromJson, boolean serializeErrorCodeFieldAsIntegerIfPossible) { return new ObjectMapper().setSerializerFactory( new ErrorContractSerializationFactory(null, excludeEmptyMetadataFromJson, serializeErrorCodeFieldAsIntegerIfPossible) ); } protected static class ErrorContractSerializationFactory extends BeanSerializerFactory { private static final String METADATA_FIELD_NAME = "metadata"; private static final String ERROR_CODE_FIELD_NAME = "code"; private final boolean excludeEmptyMetadataFromJson; private final boolean serializeErrorCodeFieldAsIntegerIfPossible; protected ErrorContractSerializationFactory(SerializerFactoryConfig config, boolean excludeEmptyMetadataFromJson, boolean serializeErrorCodeFieldAsIntegerIfPossible) { super(config); this.excludeEmptyMetadataFromJson = excludeEmptyMetadataFromJson; this.serializeErrorCodeFieldAsIntegerIfPossible = serializeErrorCodeFieldAsIntegerIfPossible; } @Override public SerializerFactory withConfig(SerializerFactoryConfig config) { return new ErrorContractSerializationFactory( config, excludeEmptyMetadataFromJson, serializeErrorCodeFieldAsIntegerIfPossible ); } @Override protected List filterBeanProperties(SerializationConfig config, BeanDescription beanDesc, List props) { List superResult = super.filterBeanProperties(config, beanDesc, props); if (DefaultErrorDTO.class.equals(beanDesc.getBeanClass())) { // Filter out empty metadata if desired if (excludeEmptyMetadataFromJson) { BeanPropertyWriter origMetadataPropWriter = findPropWriter(superResult, METADATA_FIELD_NAME); int indexOfOrig = superResult.indexOf(origMetadataPropWriter); superResult.remove(origMetadataPropWriter); superResult.add(indexOfOrig, new MetadataPropertyWriter(origMetadataPropWriter)); } // Add a smart error code writer if desired if (serializeErrorCodeFieldAsIntegerIfPossible) { BeanPropertyWriter origErrorCodePropWriter = findPropWriter(superResult, ERROR_CODE_FIELD_NAME); int indexOfOrig = superResult.indexOf(origErrorCodePropWriter); superResult.remove(origErrorCodePropWriter); superResult.add(indexOfOrig, new SmartErrorCodePropertyWriter(origErrorCodePropWriter)); } } return superResult; } protected BeanPropertyWriter findPropWriter(List propWriters, String desiredFieldName) { for (BeanPropertyWriter propWriter : propWriters) { if (desiredFieldName.equals(propWriter.getName())) { return propWriter; } } return null; } } protected static class MetadataPropertyWriter extends BeanPropertyWriter { protected MetadataPropertyWriter(BeanPropertyWriter base) { super(base); } @Override public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception { if (bean instanceof DefaultErrorDTO error) { if (error.metadata == null || error.metadata.isEmpty()) { return; // empty metadata. Don't serialize } } super.serializeAsField(bean, jgen, prov); } } protected static class SmartErrorCodePropertyWriter extends BeanPropertyWriter { protected SmartErrorCodePropertyWriter(BeanPropertyWriter base) { super(base); } @Override public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception { if (bean instanceof DefaultErrorDTO error) { try { int codeAsInt = Integer.parseInt(error.code); jgen.writeFieldName(_name); jgen.writeNumber(codeAsInt); return; } catch (Throwable t) { // Do nothing - let it be serialized normally as a string. } } super.serializeAsField(bean, jgen, prov); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy