View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.catalog.config;
18  
19  import java.io.IOException;
20  import java.time.DateTimeException;
21  import java.time.LocalDate;
22  import java.time.LocalDateTime;
23  import java.time.ZonedDateTime;
24  import java.time.format.DateTimeFormatter;
25  
26  import com.fasterxml.jackson.annotation.JsonInclude;
27  import com.fasterxml.jackson.core.JsonGenerator;
28  import com.fasterxml.jackson.core.JsonParser;
29  import com.fasterxml.jackson.core.JsonProcessingException;
30  import com.fasterxml.jackson.databind.DeserializationContext;
31  import com.fasterxml.jackson.databind.JsonDeserializer;
32  import com.fasterxml.jackson.databind.JsonMappingException;
33  import com.fasterxml.jackson.databind.JsonSerializer;
34  import com.fasterxml.jackson.databind.ObjectMapper;
35  import com.fasterxml.jackson.databind.SerializationFeature;
36  import com.fasterxml.jackson.databind.SerializerProvider;
37  import com.fasterxml.jackson.databind.module.SimpleModule;
38  import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
39  
40  /**
41   *  Extends Jackson ObjectMapper to support Java LocalDateTime.
42   */
43  public final class JsonObjectMapperFactory {
44      /**
45       * Date/Time format.
46       */
47      private static final String LOCAL_DATE_TIME_FORMAT = "yyyyMMddHHmmss.SSS";
48  
49      /**
50       * LocalDateTime formatter that converts to and from a format usable in REST requests.
51       */
52      private static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_FORMAT);
53  
54      /**
55       * Date/Time format.
56       */
57      private static final String LOCAL_DATE_FORMAT = "yyyyMMdd";
58  
59      /**
60       * LocalDateTime formatter that converts to and from a format usable in REST requests.
61       */
62      private static final DateTimeFormatter LOCAL_DATE_FORMATTER = DateTimeFormatter.ofPattern(LOCAL_DATE_FORMAT);
63  
64      /**
65       * Date/Time format.
66       */
67      private static final String ZONED_DATE_TIME_FORMAT = "yyyyMMddHHmmss.SSSZ";
68  
69      /**
70       * LocalDateTime formatter that converts to and from a format usable in REST requests.
71       */
72      public static final DateTimeFormatter ZONED_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(ZONED_DATE_TIME_FORMAT);
73  
74      private JsonObjectMapperFactory() {
75      }
76  
77      /**
78       * Create an ObjectMapper using the standard LocalDateTime format.
79       * @return The ObjectMapper.
80       */
81      public static ObjectMapper createMapper() {
82          ObjectMapper mapper = Jackson2ObjectMapperBuilder.json().build();
83          DateTimeFormatter dateTimeFormatter = LOCAL_DATE_TIME_FORMATTER;
84          DateTimeFormatter dateFormatter = LOCAL_DATE_FORMATTER;
85          DateTimeFormatter zonedTimeFormatter = ZONED_DATE_TIME_FORMATTER;
86          SimpleModule module = new SimpleModule();
87          module.addSerializer(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
88              @Override
89              public void serialize(LocalDateTime localDateTime, JsonGenerator jsonGenerator,
90                      SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
91                  jsonGenerator.writeString(dateTimeFormatter.format(localDateTime));
92              }
93          });
94          module.addDeserializer(LocalDateTime.class, new JsonDeserializer<LocalDateTime>() {
95              @Override
96              public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
97                  String string = parser.getText().trim();
98                  if (string.length() == 0) {
99                      return null;
100                 }
101                 try {
102                     return LocalDateTime.parse(string, dateTimeFormatter);
103                 } catch (DateTimeException e) {
104                     throw JsonMappingException.from(parser,
105                             String.format("Failed to deserialize %s: (%s) %s",
106                                     handledType().getName(), e.getClass().getName(), e.getMessage()), e);
107                 }
108             }
109         });
110         module.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
111             @Override
112             public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator,
113                     SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
114                 jsonGenerator.writeString(zonedTimeFormatter.format(zonedDateTime));
115             }
116         });
117         module.addDeserializer(ZonedDateTime.class, new JsonDeserializer<ZonedDateTime>() {
118             @Override
119             public ZonedDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
120                 String string = parser.getText().trim();
121                 if (string.length() == 0) {
122                     return null;
123                 }
124                 try {
125                     return ZonedDateTime.parse(string, zonedTimeFormatter);
126                 } catch (DateTimeException e) {
127                     throw JsonMappingException.from(parser,
128                             String.format("Failed to deserialize %s: (%s) %s",
129                                     handledType().getName(), e.getClass().getName(), e.getMessage()), e);
130                 }
131             }
132         });
133         module.addSerializer(LocalDate.class, new JsonSerializer<LocalDate>() {
134             @Override
135             public void serialize(LocalDate localDate, JsonGenerator jsonGenerator,
136                     SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
137                 jsonGenerator.writeString(dateFormatter.format(localDate));
138             }
139         });
140         module.addDeserializer(LocalDate.class, new JsonDeserializer<LocalDate>() {
141             @Override
142             public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
143                 String string = parser.getText().trim();
144                 if (string.length() == 0) {
145                     return null;
146                 }
147                 try {
148                     return LocalDate.parse(string, dateFormatter);
149                 } catch (DateTimeException e) {
150                     throw JsonMappingException.from(parser,
151                             String.format("Failed to deserialize %s: (%s) %s",
152                                     handledType().getName(), e.getClass().getName(), e.getMessage()), e);
153                 }
154             }
155         });
156         mapper.registerModule(module);
157         mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
158         mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
159         return mapper;
160     }
161 
162 }