ObjectMapper

一卷旌收千骑虏,万全身出百重围。这篇文章主要讲述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 =https://www.songbingjia.com/android/= 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()); } }

【ObjectMapper】 

    推荐阅读