View Javadoc
1   package top.infra.jackson2;
2   
3   import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_INTROSPECTOR;
4   import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_MODULE;
5   import static top.infra.jackson2.JaxbAnnotationJackson2MapperCustomizerFactory.CLASS_JAXB_ANNOTATION_MODULE_PRIORITY;
6   
7   import com.fasterxml.jackson.databind.Module;
8   import com.fasterxml.jackson.databind.ObjectMapper;
9   
10  import lombok.extern.slf4j.Slf4j;
11  
12  import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
13  
14  import java.lang.reflect.Method;
15  import java.util.List;
16  import java.util.Optional;
17  
18  import top.infra.common.ClassUtils;
19  import top.infra.common.EnumUtils;
20  
21  
22  /**
23   * see: http://wiki.fasterxml.com/JacksonJAXBAnnotations see: https://github.com/FasterXML/jackson-module-jaxb-annotations
24   */
25  @Slf4j
26  public class JaxbAnnotationJackson2Customizer implements Jackson2Customizer {
27  
28      @Override
29      public void customize(final Jackson2Properties properties, final ObjectMapper mapper) {
30          final Boolean isXmlMapper = this.isXmlMapper(mapper);
31  
32          if (properties.getJaxb().getEnabled()) {
33              final Optional<Module> module = this.jaxbAnnotationModule(isXmlMapper);
34              module.ifPresent(mapper::registerModule);
35          }
36      }
37  
38      @Override
39      public void customize(final Jackson2Properties properties, final Jackson2ObjectMapperBuilder builder) {
40          final Boolean isXmlMapper = this.isXmlMapper(builder);
41  
42          if (properties.getJaxb().getEnabled()) {
43              final Optional<Module> jaxbAnnotationModule = this.jaxbAnnotationModule(isXmlMapper);
44              if (jaxbAnnotationModule.isPresent()) {
45                  final List<Module> modules = this.modules(builder);
46                  modules.add(jaxbAnnotationModule.get());
47                  builder.modulesToInstall(modules.toArray(new Module[0]));
48              }
49          }
50      }
51  
52      private Optional<Module> jaxbAnnotationModule(final Boolean isXmlMapper) {
53          final Optional<Module> jaxbAnnotationModule = this.jaxbAnnotationModule();
54  
55          final Optional<Object> priority = this.priority(isXmlMapper);
56          if (jaxbAnnotationModule.isPresent() && priority.isPresent()) {
57              this.setJaxbAnnotationModulePriority(jaxbAnnotationModule.get(), priority.get());
58          }
59  
60          return jaxbAnnotationModule;
61      }
62  
63      private Optional<Module> jaxbAnnotationModule() {
64          try {
65              final Optional<Module> module;
66              final Optional<Class<?>> moduleClass = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE);
67              final Optional<Class<?>> introspectorClass = ClassUtils.forName(CLASS_JAXB_ANNOTATION_INTROSPECTOR);
68              if (moduleClass.isPresent() && introspectorClass.isPresent()) {
69                  module = Optional.of((Module) moduleClass.get().getConstructor(introspectorClass.get()) //
70                      .newInstance(new HackedJackson2JaxbAnnotationIntrospector()));
71              } else {
72                  module = Optional.empty();
73              }
74  
75              return module;
76          } catch (final ReflectiveOperationException ex) {
77              log.info("JaxbAnnotationModule config error", ex);
78  
79              return Optional.empty();
80          }
81      }
82  
83      private Optional<Object> priority(final Boolean isXmlMapper) {
84          final Optional<Object> priority;
85  
86          final String priorityName = isXmlMapper ? "PRIMARY" : "SECONDARY";
87  
88          final Class<?> enumType = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE_PRIORITY).orElse(null);
89          priority = Optional.ofNullable(enumType != null ? EnumUtils.objectValueOf(enumType, priorityName) : null);
90          return priority;
91      }
92  
93      private void setJaxbAnnotationModulePriority(final Module jaxbAnnotationModule, final Object priority) {
94          try {
95              final Class<?> enumType = ClassUtils.forName(CLASS_JAXB_ANNOTATION_MODULE_PRIORITY).orElse(null);
96              final Method setPriorityMethod = jaxbAnnotationModule.getClass().getDeclaredMethod("setPriority", enumType);
97              setPriorityMethod.invoke(jaxbAnnotationModule, priority);
98          } catch (final ReflectiveOperationException ex) {
99              log.info("JaxbAnnotationModule config error", ex);
100         }
101     }
102 }