I have a Hibernate entity with a lazy attribute.
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Entity
#Table(name = "rule", schema = "mariott_rule")
#DynamicUpdate // this is important
public class Rule {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "rule_id")
private Long id;
#Column(name = "switch")
private boolean switched;
#Column(name = "rule_name")
private String name;
private String description;
#Column(name = "date_update")
private ZonedDateTime dateUpdated;
#Column(name = "param_values", columnDefinition = "text")
#Convert(converter = RuleParamValuesAttributeConverter.class)
#Basic(fetch = LAZY)
private RuleParamValuesValidatedEntity paramValues;
}
And I have two methods that can either switch off or switch on the rule. Before switching the rule on we have be sure that paramValues are valid. That's why we fetch them with a separate query. But for the vice-versa operation it's not important. So, paramValues are not loaded in this case.
But here comes the strange part. The switching on operation generates the expected SQL.
validateParamValues(rule.getParamValues());
ruleRepository.saveAndFlush(
rule.asBuilder()
.switched(true)
.dateUpdated(now)
.build();
);
update mariott_rule.rule set date_update=?, switch=? where rule_id=?
Meantime the switching off operation adds paramValues to result SQL and assigns its value to "null" (the string value of null word).
// NO param values fetching
ruleRepository.saveAndFlush(
rule.asBuilder()
.switched(false)
.dateUpdated(now)
.build();
);
update mariott_rule.rule set date_update=?, param_values=?, switch=? where rule_id=?
binding parameter [1] as [TIMESTAMP] - [2021-04-09T08:10:28.423406Z]
binding parameter [2] as [VARCHAR] - [null]
binding parameter [3] as [BOOLEAN] - [false]
binding parameter [4] as [BIGINT] - [1]
Perhaps it's something about RuleParamsValuesAttributeConverter.class.
I removed the Basic(fetch = LAZY). Though it did help that's not what I want. Any ideas?
P.S. BTW, when I removed Basic(fetch = LAZY) it seems that #DynamicUpdate stopped to work either.
EDIT:
Here is the JsonAttributeConverter and RuleParamValuesAttributeConverter
#Slf4j
#RequiredArgsConstructor
public abstract class JsonAttributeConverter<A> implements AttributeConverter<A, String> {
private final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
private final Class<A> entityClass;
private final String dbColumnName;
private final A defaultValue;
#Override
public String convertToDatabaseColumn(A attribute) {
try {
return objectMapper.writeValueAsString(attribute);
} catch (Exception e) {
throw new ConvertException(String.format("Cannot convert %s to string", entityClass.getSimpleName()), e);
}
}
#Override
public A convertToEntityAttribute(String dbData) {
try {
return objectMapper.readValue(dbData, entityClass);
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.warn(
String.format(
"Cannot convert database column %s to the %s. The default value shall be used",
dbColumnName,
entityClass.getSimpleName()),
e
);
}
return defaultValue;
}
}
}
#Converter
public class RuleParamValuesAttributeConverter extends JsonAttributeConverter<RuleParamValuesValidatedEntity> {
public RuleParamValuesAttributeConverter() {
super(RuleParamValuesValidatedEntity.class, "mariott_rule.rule.param_values", RuleParamValuesValidatedEntity.getInvalidInstance());
}
}
Related
i do not understand why an Entity no argument constructor is being called when providing a request body? if i delete it and the only constructor that exist is the one that receive arguments, i get the expected output print, but i must implement a no argument constructor in order to save the Entity in the database.
this is the request body:
{
"str": "stringgg",
"intt": 2,
"doublee": 1.003
}
this is the route: when commenting out the empty constructor, the values of the new instance match the request json body
#PostMapping("/save")
public List<Modell> obj(#RequestBody Modell model) {
modelRepository.save(model);
System.out.println(model.toString());
return modelRepository.findAll();
}
this is the entity class:
#Table(name = "modelltbl")
#Entity
public class Modell {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "str", nullable = true)
private String str;
#Column(name = "intt", nullable = true)
private int intt;
#Column(name = "doublee", nullable = true)
private double doublee;
public Modell(String str, int intt, double doublee)
{
this.str = str;
this.intt = intt;
this.doublee = doublee;
}
public Modell(){}
#Override
public String toString()
{
return String.format("model class,params: %s , %o , %f ", str , intt, doublee);
}
}
First of all: Do not use entities iat controller level. It is bad application Design.
The json will be converted throug jackson library which creates the object by calling the default constructor and the setter of the properties. If you do not want this behavior you can use the #JsonCreator annotation.
#JsonCreator
public Modell(#JsonProperty("str")String str, #JsonProperty("intt")int intt, #JsonProperty("doublee")double doublee)
{
this.str = str;
this.intt = intt;
this.doublee = doublee;
}
I want to allow to sort by every field in the class, without having to write switch/ if statements.
My idea was to find the Field that matches given string value by name and then, with Stream API neatly sort. IntelliJ screamed that i need to surround it with try-catch, so it is not so neatly looking, but that's not important, as it does not work.
private List<MyEntity> getSorted(List<MyEntity> list, SearchCriteria criteria) {
Field sortByField = findFieldInListByName(getFieldList(MyEntity.class), criteria.getSortBy());
return list.stream().sorted(Comparator.comparing(entity-> {
try {
return (MyEntity) sortByField.get(entity);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return entity;
})).collect(Collectors.toList());
}
In the MyEntity class I have added Comparable interface, but I am not sure what should be in the body of Compare(), as I dont want to specify how to compare objects, because it will change based on the selected sorting.
EDIT: Added Entity below:
#Data
#Entity
#Table(name = "role_management", schema = "mdr")
#Builder
#NoArgsConstructor
#AllArgsConstructor
#EqualsAndHashCode
public class MyEntity implements Comparable{
#Id
#Column(name = "uuid", unique = true, insertable = false, updatable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private UUID uuid;
#ManyToOne
#JoinColumn(name = "user_id", nullable = false)
private UserEntity user;
#Basic
#NonNull
#Column(name = "role")
private String role;
#Basic
#Column(name = "action")
#Enumerated(EnumType.STRING)
private RoleAction action;
#Basic
#Column(name = "goal")
#Enumerated(EnumType.STRING)
private RoleGoal goal;
#Column(name = "date")
private LocalDateTime date;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "reporter_id", referencedColumnName = "uuid")
private UserEntity reporter;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "authorizer_id", referencedColumnName = "uuid")
private UserEntity authorizer;
#Basic
#Column(name = "ezd")
private String ezd;
#Basic
#Column(name = "is_last")
private boolean isMostRecent;
#Override
public int compareTo(Object o) {
return 0;
}
}
EDIT 2: My code based on the #Sweeper solution:
UserEntity (nullable)
#Override
public int compareTo(UserEntity other) {
if (other == null) {
return 1;
}
return this.getMail().compareTo(other.getMail());
}
Comparator:
public static Comparator getSortComparator(Field sortByField) {
return Comparator.nullsLast(Comparator.comparing(entity -> {
try {
Object fieldValue = sortByField.get(entity);
if (!(fieldValue instanceof Comparable<?>) && fieldValue != null) {
throw new IllegalArgumentException("...");
}
return (Comparable) fieldValue;
} catch (IllegalAccessException e) {
throw new MdrCommonException(e.getLocalizedMessage());
}
}));
}
MyEntity should not implement Comparable. It is the fields, by which you are going to sort the list of MyEntity objects, that needs to be Comparable. For example, if you are sorting by the field user, which is a UserEntity, then UserEntity is the thing that needs to be comparable, not MyEntity.
The lambda's job should just be to check that the fields are indeed Comparable, and throw an exception if they are not.
Since you don't know the types of the fields at compile time, however, you'd have to use a raw type here. The comparing call would look like this:
Comparator.comparing(entity -> {
try {
Object fieldValue = sortByField.get(entity);
// This check still passes if the type of fieldValue implements Comparable<U>,
// where U is an unrelated type from the type of fieldValue, but this is the
// best we can do here, since we don't know the type of field at compile time
if (!(fieldValue instanceof Comparable<?>) && fieldValue != null) {
throw new IllegalArgumentException("Field is not comparable!");
}
return (Comparable)fieldValue;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
})
You can create automatically comparators for any field of any class using reflection but is better create specific comparators (will be typechecked).
Your entity is a normal class with normal fields then, the usual Java sorting machinery should do the job:
Basically, if you define one comparator for every field (even deep fields into your entity):
public final static Comparator<MyEntity> ByField1 = comparing(MyEntity::getField1);
public final static Comparator<MyEntity> ByField2 = comparing(MyEntity::getField2);
public final static Comparator<MyEntity> ByField3 = comparing(MyEntity::getField3);
public final static Comparator<MyEntity> ByDeep1 = comparing(a -> a.getField4().getDeep1());
public final static Comparator<MyEntity> ByDeep2 = comparing(a -> a.getField4().getDeep2());
public final static Comparator<MyEntity> ByDeep3 = comparing(a -> a.getField4().getDeep3());
You can sort using complex sorting expressions:
data.stream()
.sorted(ByField2.reversed().thenComparing(ByDeep2))
.forEach(System.out::println);
a full example could be
public static void main(String[] args) {
List<MyEntity> data =
Stream.of("Row1", "Row2").flatMap(field1 ->
Stream.of(101, 102).flatMap(field2 ->
Stream.of(true, false).flatMap(field3 ->
Stream.of("Row1", "Row2").flatMap(deep1 ->
Stream.of(101, 102).flatMap(deep2 ->
Stream.of(true, false).map(deep3 ->
new MyEntity(field1, field2, field3, new MyDeepField(deep1, deep2, deep3))))))))
.collect(toList());
data.stream()
.sorted(ByField2.reversed().thenComparing(ByDeep2))
.forEach(System.out::println);
}
#Getter
#Setter
#AllArgsConstructor
static class MyDeepField {
private String deep1;
private Integer deep2;
private Boolean deep3;
}
#Getter
#Setter
#AllArgsConstructor
static class MyEntity {
private String field1;
private Integer field2;
private Boolean field3;
private MyDeepField field4;
public final static Comparator<MyEntity> ByField1 = comparing(MyEntity::getField1);
public final static Comparator<MyEntity> ByField2 = comparing(MyEntity::getField2);
public final static Comparator<MyEntity> ByField3 = comparing(MyEntity::getField3);
public final static Comparator<MyEntity> ByDeep1 = comparing(a -> a.getField4().getDeep1());
public final static Comparator<MyEntity> ByDeep2 = comparing(a -> a.getField4().getDeep2());
public final static Comparator<MyEntity> ByDeep3 = comparing(a -> a.getField4().getDeep3());
#Override
public String toString() {
return "MyEntity{" +
"field1='" + field1 + '\'' +
", field2=" + field2 +
", field3=" + field3 +
", deep1=" + field4.getDeep1() +
", deep2=" + field4.getDeep2() +
", deep3=" + field4.getDeep3() +
'}';
}
}
with output
MyEntity{field1='Row1', field2=102, field3=true, deep1=Row1, deep2=101, deep3=true}
MyEntity{field1='Row1', field2=102, field3=true, deep1=Row1, deep2=101, deep3=false}
...
MyEntity{field1='Row2', field2=101, field3=false, deep1=Row2, deep2=102, deep3=true}
MyEntity{field1='Row2', field2=101, field3=false, deep1=Row2, deep2=102, deep3=false}
The criteria field into your SearchCriteria class is some field of type Comparator<MyEntity> or a mapping using an enumeration or parsing string expressions or so...
Found a way to use an enum as the entity with its own table in JPA using Hibernate Interceptors.
For example, I want to use as an entity following enum:
#Entity
public enum Color {
RED(255, 0, 0),
GREEN(0, 255, 0),
BLUE(0, 0, 255)
#Id
public final byte id = (byte)ordinal();
#Column(unique = true, nullable = false)
public final String name = name();
#Column(nullable = false)
public final int red;
#Column(nullable = false)
public final int green;
#Column(nullable = false)
public final int blue;
}
To make JPA correctly work with that entity, we can write the following Interceptor, that converts an enum to it's ordinal to save in database:
public class EnumAsEntityInterceptor extends EmptyInterceptor {
#Override
public Object instantiate(String entityName, EntityMode entityMode, Serializable id) {
try {
Object o;
Class cls = Class.forName(entityName);
if (cls.isEnum() && id instanceof Number) {
o = cls.getEnumConstants()[((Number)id).intValue()];
} else {
o = super.getEntity(entityName, id);
}
return o;
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
After enabling this interceptor, we can work with the enum entity:
entityManager.merge(Color.RED);
But this solution works only with Hibernate. Is there a way to do similar with EclipseLink? After some research, I didn't found any functionality in EclipseLink to do that.
I'm working on a Spring Boot 2.0.5.RELEASE project.
I have a field in an Oracle database declared as CHAR(1) with a JPA converter as follows:
public class CharToBooleanConverter implements AttributeConverter<String, Boolean> {
#Override
public Boolean convertToDatabaseColumn(String s) {
return s.equalsIgnoreCase("t");
}
#Override
public String convertToEntityAttribute(Boolean aBoolean) {
if(aBoolean.equals(true)){
return "t";
} else {
return "f";
}
}
}
This converter is used in my StructureElement class twice:
#Entity
#Table(name = "OBS_STRUCTURE_ELEMENT2")
#SequenceGenerator(name = "structure_element_seq", sequenceName = "structure_element_seq", allocationSize = 1)
public class StructureElement {
#Id
#Column(name = "NO_ELEMENT")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "structure_element_seq")
private long id;
#Column(name = "TAG")
private String tag;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "SUITE")
private int sequence;
#Column(name = "OPTIONNEL")
#Convert(converter = CharToBooleanConverter.class)
private boolean optional;
#Column(name = "REPETITIF")
#Convert(converter = CharToBooleanConverter.class)
private boolean repetitive;
#ManyToOne
#JoinColumn(name = "NOM_STRUCTURE_TYPE")
private Structure typeStructure;
#Embedded
private PersistenceSignature signature;
}
The problem is that when I try to send a Structure through a RestController I receive the following in console:
Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Could not set field value [t] value by reflection : [class be.solodoukhin.domain.StructureElement.optional] setter of be.solodoukhin.domain.StructureElement.optional; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Could not set field value [t] value by reflection : [class be.solodoukhin.domain.StructureElement.optional] setter of be.solodoukhin.domain.StructureElement.optional (through reference chain: be.solodoukhin.domain.Structure["elements"])]
With an 500 Internal Server Error response.
Here is my method:
#RestController
#RequestMapping("/structure")
public class StructuresController {
#GetMapping("/{name}")
public ResponseEntity<Structure> getOne(#PathVariable("name") String name)
{
LOGGER.info("Call to StructuresController.getOne with name = " + name);
Optional<Structure> found = this.structureRepository.findById(name);
if(found.isPresent()){
return ResponseEntity.ok(found.get());
}
else
{
return ResponseEntity.badRequest().body(null);
}
}
}
I've tried to use hibernate specific annotation #Type(type = "true_false"). It works but this produces an uppercase T or F in the database.
I've tried to write a JSON serializer that extends com.fasterxml.jackson.databind.ser.std.StdSerializer using this link without success.
Isn't your converter the wrong way round? Your convertToDatabaseColumn has it going from a String to a Boolean. Surely you want it going from Boolean to String. And the convertToEntityAttribute going from String to Boolean.
I suspect that the convert is returning a value of "t" or "f" which can't then be put into the boolean field in the entity.
I think it should be...
public class CharToBooleanConverter implements AttributeConverter<Boolean, String> {
#Override
public Boolean convertToEntityAttribute(String s) {
return s != null && s.equalsIgnoreCase("t");
}
#Override
public String convertToDatabaseColumn(Boolean aBoolean) {
return (aBoolean != null && aBoolean) ? "t" : "f";
}
}
I have a MySQL column declared as type JSON and I have problems to map it with JPA/Hibernate. I'm using Spring Boot on back-end.
Here is small part of my code:
#Entity
#Table(name = "some_table_name")
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "json_value")
private JSONArray jsonValue;
The program returns me an error and tells me that I can't map the column.
In mysql table the column is defined as:
json_value JSON NOT NULL;
You don’t have to create all these types manually, you can simply get
them via Maven Central using the following dependency:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
For more info, check out the Hibernate Types open-source project.
Now, to explain how it all works.
Assuming you have the following entity:
#Entity(name = "Book")
#Table(name = "book")
#TypeDef(
name = "json",
typeClass = JsonType.class
)
public class Book {
#Id
#GeneratedValue
private Long id;
#NaturalId
private String isbn;
#Type(type = "json")
#Column(columnDefinition = "json")
private String properties;
//Getters and setters omitted for brevity
}
Notice two things in the code snippet above:
the #TypeDef is used to define a new custom Hibernate Type, json which is handled by the JsonType
the properties attribute has a json column type and it's mapped as a String
That's it!
Now, if you save an entity:
Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99" +
"}"
);
entityManager.persist(book);
Hibernate is going to generate the following SQL statement:
INSERT INTO
book
(
isbn,
properties,
id
)
VALUES
(
'978-9730228236',
'{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99}',
1
)
And you can also load it back and modify it:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"url\": \"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/\"" +
"}"
);
Hibernate taking caare of the UPDATE statement for you:
SELECT b.id AS id1_0_
FROM book b
WHERE b.isbn = '978-9730228236'
SELECT b.id AS id1_0_0_ ,
b.isbn AS isbn2_0_0_ ,
b.properties AS properti3_0_0_
FROM book b
WHERE b.id = 1
UPDATE
book
SET
properties = '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99,"url":"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/"}'
WHERE
id = 1
All code available on GitHub.
I prefer to do this way:
Creating converter (attribute converter) from Map to String and vice versa.
Using Map to map mysql JSON column type in domain (entity) class
The code is bellow.
JsonToMapConverted.java
#Converter
public class JsonToMapConverter
implements AttributeConverter<String, Map<String, Object>>
{
private static final Logger LOGGER = LoggerFactory.getLogger(JsonToMapConverter.class);
#Override
#SuppressWarnings("unchecked")
public Map<String, Object> convertToDatabaseColumn(String attribute)
{
if (attribute == null) {
return new HashMap<>();
}
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
}
catch (IOException e) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.");
}
return new HashMap<>();
}
#Override
public String convertToEntityAttribute(Map<String, Object> dbData)
{
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
}
catch (JsonProcessingException e)
{
LOGGER.error("Could not convert map to json string.");
return null;
}
}
}
Part of domain (entity-mapping) class
...
#Column(name = "meta_data", columnDefinition = "json")
#Convert(attributeName = "data", converter = JsonToMapConverter.class)
private Map<String, Object> metaData = new HashMap<>();
...
This solution perfectly works for me.
For anyone can't make #J. Wang answer work :
Try add this dependency(it's for hibernate 5.1 and 5.0, other version check here)
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-5</artifactId>
<version>1.2.0</version>
</dependency>
And add this line to the entity
#TypeDef(name = "json", typeClass = JsonStringType.class)
So full version of the entity class :
#Entity
#Table(name = "some_table_name")
#TypeDef(name = "json", typeClass = JsonStringType.class)
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Type( type = "json" )
#Column( columnDefinition = "json" )
private List<String> jsonValue;
}
I test the code with spring boot 1.5.9 and hibernate-types-5 1.2.0 .
If the values inside your json array are simple strings you can do this:
#Type( type = "json" )
#Column( columnDefinition = "json" )
private String[] jsonValue;
Heril Muratovic's answer is good, but I think the JsonToMapConverter should implement AttributeConverter<Map<String, Object>, String>, not AttributeConverter<String, Map<String, Object>>. Here is the code that works for me
#Slf4j
#Converter
public class JsonToMapConverter implements AttributeConverter<Map<String, Object>, String> {
#Override
#SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String attribute) {
if (attribute == null) {
return new HashMap<>();
}
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
} catch (IOException e) {
log.error("Convert error while trying to convert string(JSON) to map data structure.", e);
}
return new HashMap<>();
}
#Override
public String convertToDatabaseColumn(Map<String, Object> dbData) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
} catch (JsonProcessingException e) {
log.error("Could not convert map to json string.", e);
return null;
}
}
}
In Kotlin, the following variation/combination of the above suggestions worked for me:
#Entity
#Table(name = "product_menu")
#TypeDef(name = "json", typeClass = JsonStringType::class)
data class ProductMenu(
#Type(type = "json")
#Column(name = "menu_json", columnDefinition = "json")
#Convert(attributeName = "menuJson", converter = JsonToMapConverter::class)
val menuJson: HashMap<String, Any> = HashMap()
) : Serializable
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.databind.ObjectMapper
import org.slf4j.LoggerFactory
import java.io.IOException
import javax.persistence.AttributeConverter
class JsonToMapConverter : AttributeConverter<String, HashMap<String, Any>> {
companion object {
private val LOGGER = LoggerFactory.getLogger(JsonToMapConverter::class.java)
}
override fun convertToDatabaseColumn(attribute: String?): HashMap<String, Any> {
if(attribute == null) {
return HashMap()
}
try {
val objectMapper = ObjectMapper()
#Suppress("UNCHECKED_CAST")
return objectMapper.readValue(attribute, HashMap::class.java) as HashMap<String, Any>
} catch (e: IOException) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.")
}
return HashMap()
}
override fun convertToEntityAttribute(dbData: HashMap<String, Any>?): String? {
return try {
val objectMapper = ObjectMapper()
objectMapper.writeValueAsString(dbData)
} catch (e: JsonProcessingException) {
LOGGER.error("Could not convert map to json string.")
return null
}
}
}