1 package com.vladmihalcea.hibernate.type.util;
2
3 import com.fasterxml.jackson.databind.JavaType;
4 import com.fasterxml.jackson.databind.JsonNode;
5 import com.fasterxml.jackson.databind.type.TypeFactory;
6 import org.hibernate.internal.util.SerializationHelper;
7 import org.hibernate.type.SerializationException;
8
9 import java.io.Serializable;
10 import java.util.Collection;
11 import java.util.Map;
12
13 /**
14  * @author Vlad Mihalcea
15  */

16 public class ObjectMapperJsonSerializer implements JsonSerializer {
17
18     private final ObjectMapperWrapper objectMapperWrapper;
19
20     public ObjectMapperJsonSerializer(ObjectMapperWrapper objectMapperWrapper) {
21         this.objectMapperWrapper = objectMapperWrapper;
22     }
23
24     @Override
25     public <T> T clone(T object) {
26         if (object instanceof String) {
27             return object;
28         } else if (object instanceof Collection) {
29             Object firstElement = findFirstNonNullElement((Collection) object);
30             if (firstElement != null && !(firstElement instanceof Serializable)) {
31                 JavaType type = TypeFactory.defaultInstance().constructParametricType(object.getClass(), firstElement.getClass());
32                 return objectMapperWrapper.fromBytes(objectMapperWrapper.toBytes(object), type);
33             }
34         } else if (object instanceof Map) {
35             Map.Entry firstEntry = this.findFirstNonNullEntry((Map) object);
36             if (firstEntry != null) {
37                 Object key = firstEntry.getKey();
38                 Object value = firstEntry.getValue();
39                 if (!(key instanceof Serializable) || !(value instanceof Serializable)) {
40                     JavaType type = TypeFactory.defaultInstance().constructParametricType(object.getClass(), key.getClass(), value.getClass());
41                     return (T) objectMapperWrapper.fromBytes(objectMapperWrapper.toBytes(object), type);
42                 }
43             }
44         } else if (object instanceof JsonNode) {
45             return (T) ((JsonNode) object).deepCopy();
46         }
47
48         if (object instanceof Serializable) {
49             try {
50                 return (T) SerializationHelper.clone((Serializable) object);
51             } catch (SerializationException e) {
52                 //it is possible that object itself implements java.io.Serializable, but underlying structure does not
53                 //in this case we switch to the other JSON marshaling strategy which doesn't use the Java serialization
54             }
55         }
56
57         return jsonClone(object);
58     }
59
60     private Object findFirstNonNullElement(Collection collection) {
61         for (java.lang.Object element : collection) {
62             if (element != null) {
63                 return element;
64             }
65         }
66         return null;
67     }
68
69     private Map.Entry findFirstNonNullEntry(Map<?, ?> map) {
70         for (Map.Entry entry : map.entrySet()) {
71             if (entry.getKey() != null && entry.getValue() != null) {
72                 return entry;
73             }
74         }
75         return null;
76     }
77
78     private <T> T jsonClone(T object) {
79         return objectMapperWrapper.fromBytes(objectMapperWrapper.toBytes(object), (Class<T>) object.getClass());
80     }
81 }