View Javadoc
1   package top.infra.jackson2;
2   
3   import static java.util.stream.Collectors.toList;
4   
5   import com.fasterxml.jackson.core.JsonProcessingException;
6   import com.fasterxml.jackson.core.type.TypeReference;
7   import com.fasterxml.jackson.databind.ObjectMapper;
8   
9   import lombok.extern.slf4j.Slf4j;
10  
11  import org.springframework.beans.BeanUtils;
12  import org.springframework.core.OrderComparator;
13  
14  import java.io.IOException;
15  import java.util.List;
16  import java.util.Objects;
17  import java.util.Set;
18  import java.util.function.Function;
19  
20  import top.infra.common.ClassUtils;
21  
22  /**
23   * Created by zhanghaolun on 16/6/9.
24   */
25  @Slf4j
26  public abstract class Jackson2Utils {
27  
28      private static Boolean JACKSON2_PRESENT;
29  
30      static {
31          JACKSON2_PRESENT = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper")
32              && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator");
33      }
34  
35      private Jackson2Utils() {
36      }
37  
38      /**
39       * Setup a Mapper.
40       *
41       * @param properties   jackson2Properties
42       * @param objectMapper ObjectMapper or XmlMapper to customize
43       * @return objectMapper
44       */
45      public static ObjectMapper customize(final Jackson2Properties properties, final ObjectMapper objectMapper) {
46          for (final Jackson2MapperCustomizer customizer : jackson2MapperCustomizers()) {
47              log.info("customize objectMapper: '{}' using: '{}'.", objectMapper, customizer);
48              customizer.customize(properties, objectMapper);
49          }
50          return objectMapper;
51      }
52  
53      public static <T> Function<String, T> fromJson( //
54          final ObjectMapper objectMapper, //
55          final TypeReference<T> typeReference //
56      ) {
57          return string -> {
58              try {
59                  return objectMapper.readValue(string, typeReference);
60              } catch (final IOException wrapped) {
61                  throw new RuntimeJsonProcessingException("error read from JSON.", wrapped);
62              }
63          };
64      }
65  
66      /**
67       * parse JSON.
68       *
69       * @param objectMapper objectMapper
70       * @param type         type
71       * @param <T>          type
72       * @return object
73       */
74      public static <T> Function<String, T> fromJson( //
75          final ObjectMapper objectMapper, //
76          final Class<T> type //
77      ) {
78          return string -> {
79              try {
80                  return objectMapper.readValue(string, type);
81              } catch (final IOException wrapped) {
82                  throw new RuntimeJsonProcessingException("error read from JSON.", wrapped);
83              }
84          };
85      }
86  
87      public static Boolean isJackson2Present() {
88          return Jackson2Utils.JACKSON2_PRESENT;
89      }
90  
91      static List<Jackson2MapperCustomizer> jackson2MapperCustomizers() {
92          final List<Jackson2MapperCustomizerFactory> factories = jackson2MapperCustomizerFactories();
93  
94          return factories.stream()
95              .map(factory -> factory.getObject().orElse(null))
96              .filter(Objects::nonNull)
97              .sorted(OrderComparator.INSTANCE)
98              .collect(toList());
99      }
100 
101     static List<Jackson2MapperCustomizerFactory> jackson2MapperCustomizerFactories() {
102         final String basePackage = Jackson2Utils.class.getName().split("\\.")[0];
103 
104         final Set<Class<Jackson2MapperCustomizerFactory>> classes = ClassUtils.FileAndClasspathUtils.scan(basePackage,
105             new ClassUtils.FileAndClasspathUtils.AssignableFilter(Jackson2MapperCustomizerFactory.class, false, false));
106 
107         log.info("found {} jackson2MapperCustomizerFactories.", classes.size());
108 
109         return classes.stream().map(BeanUtils::instantiate).collect(toList());
110     }
111 
112     /**
113      * to JSON.
114      *
115      * @param objectMapper objectMapper
116      * @param <T>          type
117      * @return JSON
118      */
119     public static <T> Function<T, String> toJson(final ObjectMapper objectMapper) {
120         return object -> {
121             try {
122                 if (object != null) {
123                     return objectMapper.writeValueAsString(object);
124                 } else {
125                     return "";
126                 }
127             } catch (final JsonProcessingException wrapped) {
128                 throw new RuntimeJsonProcessingException("error serialize to JSON.", wrapped);
129             }
130         };
131     }
132 
133     public static <T> String toJson(final ObjectMapper objectMapper, final T item) {
134         return toJson(objectMapper).apply(item);
135     }
136 
137     public static class RuntimeJsonProcessingException extends RuntimeException {
138 
139         private static final long serialVersionUID = 1L;
140 
141         public RuntimeJsonProcessingException(final String message, final Throwable cause) {
142             super(message, cause);
143         }
144     }
145 }