ObjectMapper

package com.citi.tm.core.position.json;

import com.citi.tm.modules.supplier.api.util.RawSerializableSupplier;
import com.citi.tm.modules.util.jackson.LombokToJavaBeansJsonPropertyNamingStrategy;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.NoArgsConstructor;

@NoArgsConstructor
public class ObjectMapperSerializableSupplier implements RawSerializableSupplier<ObjectMapper> {

  private transient ObjectMapper objectMapper;

  /**
   * Returns a configured {@link ObjectMapper} instance, creating it first if a cached instance is
   * not available.
   */
  @Override
  public ObjectMapper get() {
    if (objectMapper == null) {
      objectMapper = new ObjectMapper();
      configureObjectMapper();
    }
    return objectMapper;
  }

  private void configureObjectMapper() {
    configurePropertyNamingStrategy();
    configureDateAndTimeMapping();

    objectMapper.setSerializationInclusion(Include.NON_NULL);
  }

  /**
   * Configures custom property naming strategy to correctly handle field names starting with a
   * single lowercase letter.
   *
   * @see LombokToJavaBeansJsonPropertyNamingStrategy
   */
  private void configurePropertyNamingStrategy() {
    objectMapper
        .setPropertyNamingStrategy(new LombokToJavaBeansJsonPropertyNamingStrategy())
        // required for LombokToJavaBeansJsonPropertyNamingStrategy
        .configure(MapperFeature.USE_STD_BEAN_NAMING, true);
  }

  /**
   * The output of {@link com.fasterxml.jackson.databind.ObjectMapper} with default configuration
   * for {@link java.time.LocalDate}, {@link java.time.LocalTime} and {@link
   * java.time.LocalDateTime} is very complex structure.
   *
   * <p>The following configuration allows displaying date and time according ISO 8601 format:
   *
   * <ul>
   *   <li>YYY-MM-DD for date
   *   <li>hh:mm:ss.sssZ for time
   *   <li>YYY-MM-DDThh:mm:ss.sssZ for datetime
   * </ul>
   */
  private void configureDateAndTimeMapping() {
    objectMapper
        .registerModule(new JavaTimeModule())
        .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
  }
}
public interface RawSerializableSupplier<T> extends Supplier<T>, Serializable {}
package com.citi.tm.api.core.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import org.springframework.boot.jackson.JsonComponent;

/**
 * Custom JSON serializer for Date objects.
 *
 * <p>By default, {@link java.util.Date} objects are serialized to string in the format like:
 * '2018-01-01T00:00:00.000+0000'. This is different from the format returned e.g. by the {@link
 * java.time.Instant} serializer ('2018-01-01T00:00:00Z'). {@code java.util.Date} is used to
 * represent date and time in MongoDB BSON documents, so if one API endpoint returns raw BSON
 * document from the database, and another returns a Java model class, there is an inconsistency in
 * date formats returned by the API. To remove this inconsistency, this component serializes {@code
 * java.util.Date} objects to ISO-8601 format with zone offset ID (e.g. '2018-01-01T00:00:00Z').
 */
@JsonComponent
public class DateSerializer extends JsonSerializer<Date> {

  @Override
  public void serialize(
      Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
      throws IOException {

    String dateString = DateTimeFormatter.ISO_INSTANT.format(date.toInstant());
    jsonGenerator.writeString(dateString);
  }
}
package com.citi.tm.api.core.jackson;

import static org.assertj.core.api.Assertions.*;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;

public class DateSerializerTest {

  private ObjectMapper objectMapper;

  @Before
  public void setUp() {
    objectMapper = new ObjectMapper();

    SimpleModule module = new SimpleModule();
    module.addSerializer(Date.class, new DateSerializer());
    objectMapper.registerModule(module);
  }

  @Test
  public void shouldSerializeDateToIsoFormatWithOffsetId() throws JsonProcessingException {
    // given
    Date date =
        Date.from(LocalDateTime.of(2018, 1, 1, 0, 0, 0).atOffset(ZoneOffset.UTC).toInstant());

    // when
    String serializedDate = objectMapper.writeValueAsString(date);

    // then
    assertThat(serializedDate).isEqualTo("\"2018-01-01T00:00:00Z\"");
  }
}
package com.citi.tm.api.core.jackson;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import org.bson.types.ObjectId;
import org.springframework.boot.jackson.JsonComponent;

@JsonComponent
public class ObjectIdSerializer extends JsonSerializer<ObjectId> {

  @Override
  public void serialize(
      ObjectId objectId, JsonGenerator jsonGenerator, SerializerProvider serializers)
      throws IOException {
    jsonGenerator.writeString(objectId.toString());
  }
}
package com.citi.tm.api.core.jackson;

import static org.assertj.core.api.Assertions.*;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import org.bson.types.ObjectId;
import org.junit.Test;

public class ObjectIdSerializerTest {

  @Test
  public void shouldWriteMongoObjectIdAsStringAfterConfiguration() throws Exception {
    // given
    SimpleModule customSerializers = new SimpleModule();
    customSerializers.addSerializer(ObjectId.class, new ObjectIdSerializer());
    ObjectMapper objectMapper = new ObjectMapper().registerModule(customSerializers);

    // when
    String json = objectMapper.writeValueAsString(new ObjectId("1930190f7d12ee21c0c4a7cc"));

    // then
    assertThat(json).isEqualTo("\"1930190f7d12ee21c0c4a7cc\"");
  }
}
package com.citi.tm.api.core.paging;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.util.Collection;
import java.util.Map;
import java.util.stream.Collectors;
import org.springframework.util.LinkedMultiValueMap;

/**
 * Preparation HAL link next requires conversion criteria to HTTP URL query.
 *
 * <p>This is reverse operation vs MVC mapping from HTTP request to POJO
 *
 * <p>Criteria, being plain Java objects, are converted to Spring MultiValueMap which is part of
 * Spring URI Builder API
 */
public class MultiMapUtil {

  /**
   * MultiMapUtil use self configured objectMapper instead of global one from Spring Boot
   *
   * <p>Created MultiMap is used to construct next request URI by uriBuilder. The URI must be
   * compatible with Spring MVC data binder. Especially, dates must be bind-able.
   *
   * <p>Spring MVC data binder is not related to global JSON configuration. Therefore this setup is
   * also not related to global JSON configuration
   */
  private static final ObjectMapper objectMapper;

  static {
    objectMapper = new ObjectMapper();
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.setSerializationInclusion(Include.NON_NULL);
  }

  public static LinkedMultiValueMap<String, String> convertToMultiMap(Object... request) {

    LinkedMultiValueMap<String, String> result = new LinkedMultiValueMap<>();

    if (request == null) {
      return result;
    }

    for (Object criteria : request) {
      addCriteriaToResult(result, criteria);
    }

    return result;
  }

  protected static void addCriteriaToResult(
      LinkedMultiValueMap<String, String> result, Object criteria) {
    if (criteria != null) {
      Map<String, Object> criteriaMap = objectMapper.convertValue(criteria, Map.class);

      criteriaMap.forEach(
          (key, value) -> {
            if (value instanceof Collection<?>) {
              ((Collection<?>) value).forEach(element -> result.add(key, element.toString()));
            } else if (value != null) {
              result.add(key, value.toString());
            }
            // if value == null skip
          });
    }
  }

  public static LinkedMultiValueMap<String, String> convertToMultiMapAndSort(Object... request) {
    return sort(convertToMultiMap(request));
  }

  /*
   * Sorted output is expected to be more readable. Sorting is not formal requirement
   */
  private static LinkedMultiValueMap<String, String> sort(
      LinkedMultiValueMap<String, String> input) {
    return input.entrySet().stream()
        .sorted(Map.Entry.comparingByKey())
        .collect(
            Collectors.toMap(
                Map.Entry::getKey,
                Map.Entry::getValue,
                (oldValue, newValue) -> oldValue,
                LinkedMultiValueMap::new));
  }

  private MultiMapUtil() {}
}
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;


  private static final ObjectMapper objectMapper;


  static {
    SimpleModule simpleModule = new SimpleModule();
    simpleModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
    objectMapper = new ObjectMapper();
    objectMapper.registerModule(simpleModule);
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.setSerializationInclusion(Include.NON_NULL);
  }

  private Document mapToDoc(CollateralRepresentation trade) {
    try {
      Document doc = Document.parse(objectMapper.writeValueAsString(trade));
      doc.remove("id");
      return doc;
    } catch (JsonProcessingException e) {
      throw new ResponseStatusException(
          HttpStatus.INTERNAL_SERVER_ERROR,
          "Unable to serialize trade, trade id is "
              + trade.getId()
              + " uicid is "
              + trade.getUicid());
    }
  }

猜你喜欢

转载自www.cnblogs.com/tonggc1668/p/13189143.html