mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-17 04:30:45 +00:00
add toYamlCustomized / toJsonCustomized methods, that expose jackson's now-preferred Builder objects to be configured on instead of doing config directly on mapper objects.
This commit is contained in:
@ -37,6 +37,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.json.JsonMapper;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
@ -84,6 +85,7 @@ public class JsonUtils
|
||||
** Internally using jackson - so jackson annotations apply!
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Deprecated(since = "since toJsonCustomized was added, which uses jackson's newer builder object for customization")
|
||||
public static String toJson(Object object, Consumer<ObjectMapper> objectMapperCustomizer)
|
||||
{
|
||||
try
|
||||
@ -105,6 +107,34 @@ public class JsonUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Serialize any object into a JSON String - with customizations on the Jackson
|
||||
** ObjectMapper.
|
||||
**
|
||||
** Internally using jackson - so jackson annotations apply!
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static String toJsonCustomized(Object object, Consumer<JsonMapper.Builder> jsonMapperCustomizer)
|
||||
{
|
||||
try
|
||||
{
|
||||
JsonMapper.Builder jsonMapperBuilder = newJsonMapperBuilder();
|
||||
if(jsonMapperCustomizer != null)
|
||||
{
|
||||
jsonMapperCustomizer.accept(jsonMapperBuilder);
|
||||
}
|
||||
String jsonResult = jsonMapperBuilder.build().writeValueAsString(object);
|
||||
return (jsonResult);
|
||||
}
|
||||
catch(JsonProcessingException e)
|
||||
{
|
||||
LOG.error("Error serializing object of type [" + object.getClass().getSimpleName() + "] to json", e);
|
||||
throw new IllegalArgumentException("Error in JSON Serialization", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Serialize any object into a "pretty" / formatted JSON String.
|
||||
**
|
||||
@ -168,7 +198,6 @@ public class JsonUtils
|
||||
/*******************************************************************************
|
||||
** De-serialize a json string into an object of the specified class - with
|
||||
** customizations on the Jackson ObjectMapper.
|
||||
**.
|
||||
**
|
||||
** Internally using jackson - so jackson annotations apply!
|
||||
**
|
||||
@ -242,6 +271,23 @@ public class JsonUtils
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Standard private method to build jackson JsonMapperBuilder with standard features.
|
||||
**
|
||||
*******************************************************************************/
|
||||
private static JsonMapper.Builder newJsonMapperBuilder()
|
||||
{
|
||||
JsonMapper.Builder jsonMapperBuilder = JsonMapper.builder();
|
||||
jsonMapperBuilder.addModule(new JavaTimeModule());
|
||||
jsonMapperBuilder.serializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
jsonMapperBuilder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
jsonMapperBuilder.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
jsonMapperBuilder.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
|
||||
|
||||
return (jsonMapperBuilder);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** Standard private method to build jackson ObjectMapper with standard features.
|
||||
**
|
||||
|
@ -26,9 +26,11 @@ import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
|
||||
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
|
||||
import com.kingsrook.qqq.backend.core.logging.QLogger;
|
||||
|
||||
|
||||
@ -62,7 +64,7 @@ public class YamlUtils
|
||||
*******************************************************************************/
|
||||
public static String toYaml(Object object)
|
||||
{
|
||||
return toYaml(object, null);
|
||||
return toYamlCustomized(object, null);
|
||||
}
|
||||
|
||||
|
||||
@ -70,6 +72,7 @@ public class YamlUtils
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Deprecated(since = "since toYamlCustomized was added, which uses jackson's newer builder object for customization")
|
||||
public static String toYaml(Object object, Consumer<ObjectMapper> objectMapperCustomizer)
|
||||
{
|
||||
try
|
||||
@ -96,4 +99,36 @@ public class YamlUtils
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public static String toYamlCustomized(Object object, Consumer<YAMLMapper.Builder> yamlMapperCustomizer)
|
||||
{
|
||||
try
|
||||
{
|
||||
YAMLFactory yamlFactory = new YAMLFactory()
|
||||
.disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER);
|
||||
|
||||
YAMLMapper.Builder yamlMapperBuilder = YAMLMapper.builder(yamlFactory);
|
||||
yamlMapperBuilder.serializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
yamlMapperBuilder.serializationInclusion(JsonInclude.Include.NON_EMPTY);
|
||||
|
||||
if(yamlMapperCustomizer != null)
|
||||
{
|
||||
yamlMapperCustomizer.accept(yamlMapperBuilder);
|
||||
}
|
||||
|
||||
YAMLMapper yamlMapper = yamlMapperBuilder.build();
|
||||
yamlMapper.findAndRegisterModules();
|
||||
return (yamlMapper.writeValueAsString(object));
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.error("Error serializing object of type [" + object.getClass().getSimpleName() + "] to yaml", e);
|
||||
throw new IllegalArgumentException("Error in YAML Serialization", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,9 +24,11 @@ package com.kingsrook.qqq.backend.core.utils;
|
||||
|
||||
import java.util.Map;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.kingsrook.qqq.backend.core.BaseTest;
|
||||
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -60,6 +62,47 @@ class YamlUtilsTest extends BaseTest
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* simple bean to use in customObjectMapper test
|
||||
* we'd use a map, but SORT_PROPERTIES_ALPHABETICALLY doesn't apply to maps...
|
||||
***************************************************************************/
|
||||
private record SomeBean(String foo, Integer bar) {}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@Test
|
||||
void testCustomObjectMapper() throws JsonProcessingException
|
||||
{
|
||||
SomeBean someBean = new SomeBean("Hi", 47);
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
// by default, the fields come out in the order they're declared //
|
||||
///////////////////////////////////////////////////////////////////
|
||||
assertEquals("""
|
||||
foo: "Hi"
|
||||
bar: 47
|
||||
""", YamlUtils.toYaml(someBean));
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// customize the builder to sort properties alphabetically //
|
||||
// (to assert that doing a customization works) //
|
||||
/////////////////////////////////////////////////////////////
|
||||
String outputYaml = YamlUtils.toYamlCustomized(someBean, yamlMapperBuilder ->
|
||||
{
|
||||
yamlMapperBuilder.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
|
||||
});
|
||||
|
||||
assertEquals("""
|
||||
bar: 47
|
||||
foo: "Hi"
|
||||
""", outputYaml);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
|
@ -104,7 +104,7 @@ public class PublishAPI implements Callable<Integer>
|
||||
// subsets of it (e.g., grouped by table mostly) - then we'll write out each such file //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
OpenAPI openAPI = middlewareVersion.generateOpenAPIModel("qqq");
|
||||
String yaml = YamlUtils.toYaml(openAPI, mapper ->
|
||||
String yaml = YamlUtils.toYamlCustomized(openAPI, mapperBuilder ->
|
||||
{
|
||||
if(sortFileContentsForHuman)
|
||||
{
|
||||
@ -114,7 +114,7 @@ public class PublishAPI implements Callable<Integer>
|
||||
}
|
||||
else
|
||||
{
|
||||
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
|
||||
mapperBuilder.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -112,9 +112,9 @@ public class ValidateAPIVersions implements Callable<Integer>
|
||||
// generate a new spec based on current code in codebase //
|
||||
///////////////////////////////////////////////////////////
|
||||
OpenAPI openAPI = middlewareVersion.generateOpenAPIModel("qqq");
|
||||
String yaml = YamlUtils.toYaml(openAPI, mapper ->
|
||||
String yaml = YamlUtils.toYamlCustomized(openAPI, mapperBuilder ->
|
||||
{
|
||||
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
|
||||
mapperBuilder.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);
|
||||
});
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
Reference in New Issue
Block a user