真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

SpringBoot中Jackson應(yīng)用詳解

Spring Boot支持與三種JSON mapping庫(kù)集成:Gson、Jackson和JSON-B。Jackson是首選和默認(rèn)的。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站設(shè)計(jì)、成都做網(wǎng)站、移動(dòng)網(wǎng)站開(kāi)發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開(kāi)放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。創(chuàng)新互聯(lián)推出新沂免費(fèi)做網(wǎng)站回饋大家。

Jackson是spring-boot-starter-json依賴中的一部分,spring-boot-starter-web中包含spring-boot-starter-json。也就是說(shuō),當(dāng)項(xiàng)目中引入spring-boot-starter-web后會(huì)自動(dòng)引入spring-boot-starter-json。


    org.springframework.boot
    spring-boot-starter-web

Jackson

ObjectMapper

ObjectMapper是jackson-databind包中的一個(gè)類(lèi),提供讀寫(xiě)JSON的功能,可以方便的進(jìn)行對(duì)象和JSON轉(zhuǎn)換:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;

public final class JsonUtil {
    private static ObjectMapper mapper = new ObjectMapper();

    private JsonUtil() {
    }

    /**
     * Serialize any Java value as a String.
     */
    public static String generate(Object object) throws JsonProcessingException {
        return mapper.writeValueAsString(object);
    }

    /**
     * Deserialize JSON content from given JSON content String.
     */
    public static  T parse(String content, Class valueType) throws IOException {
        return mapper.readValue(content, valueType);
    }
}

編寫(xiě)一簡(jiǎn)單POJO測(cè)試類(lèi):

import java.util.Date;

public class Hero { 
    private String name;
    private Date birthday;

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new Hero("Jason", new Date())));
    }

    public Hero() {
    }

    public Hero(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

    public Date getBirthday() {
        return birthday;
    }
}

運(yùn)行后輸出結(jié)果如下:

{"name":"Jason","birthday":1540909420353}

日期轉(zhuǎn)換

上例,默認(rèn)日期轉(zhuǎn)換為長(zhǎng)整型。

ObjectMapper默認(rèn)序列化配置啟用了SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,日期將轉(zhuǎn)換為T(mén)imestamp。可查看如下源碼:

public ObjectMapper(JsonFactory jf, DefaultSerializerProvider sp, DefaultDeserializationContext dc) {
...
    BaseSettings base = DEFAULT_BASE.withClassIntrospector(defaultClassIntrospector());
    _configOverrides = new ConfigOverrides();
    _serializationConfig = new SerializationConfig(base, _subtypeResolver, mixins, rootNames, _configOverrides);
    ...
}
public SerializationConfig(BaseSettings base, SubtypeResolver str, SimpleMixInResolver mixins, RootNameLookup rootNames,
        ConfigOverrides configOverrides)
{
    super(base, str, mixins, rootNames, configOverrides);
    _serFeatures = collectFeatureDefaults(SerializationFeature.class);
    _filterProvider = null;
    _defaultPrettyPrinter = DEFAULT_PRETTY_PRINTER;
    _generatorFeatures = 0;
    _generatorFeaturesToChange = 0;
    _formatWriteFeatures = 0;
    _formatWriteFeaturesToChange = 0;
}

默認(rèn)情況下,Date類(lèi)型序列化將調(diào)用DateSerializer的_timestamp 方法:

/**
 * For efficiency, we will serialize Dates as longs, instead of
 * potentially more readable Strings.
 */
@JacksonStdImpl
@SuppressWarnings("serial")
public class DateSerializer extends DateTimeSerializerBase {
    ...

    @Override
    protected long _timestamp(Date value) {
        return (value == null) ? 0L : value.getTime();
    }

    @Override
    public void serialize(Date value, JsonGenerator g, SerializerProvider provider) throws IOException {
        if (_asTimestamp(provider)) {
            g.writeNumber(_timestamp(value));
            return;
        }
        _serializeAsString(value, g, provider);
    }
}

DateTimeSerializerBase的_asTimestamp方法:

protected boolean _asTimestamp(SerializerProvider serializers)
{
    if (_useTimestamp != null) {
        return _useTimestamp.booleanValue();
    }
    if (_customFormat == null) {
        if (serializers != null) {
            return serializers.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        }
        // 12-Jun-2014, tatu: Is it legal not to have provider? Was NPE:ing earlier so leave a check
        throw new IllegalArgumentException("Null SerializerProvider passed for "+handledType().getName());
    }
    return false;
}

禁用WRITE_DATES_AS_TIMESTAMPS
若要將日期序列化為字符串,可禁用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS:

mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

這時(shí)序列化將調(diào)用StdDateFormat的format()方法,使用ISO-8601兼容格式"yyyy-MM-dd'T'HH:mm:ss.SSSZ",輸出內(nèi)容如下:

{"name":"Jason","birthday":"2018-10-31T03:07:34.485+0000"}

StdDateFormat反序列化支持ISO-8601兼容格式和RFC-1123("EEE, dd MMM yyyy HH:mm:ss zzz")格式。

@JsonFormat
使用@JsonFormat注解,代替全局設(shè)置,是一種更靈活的方法:

@JsonFormat(shape = JsonFormat.Shape.STRING)
private Date birthday;

還可以定義pattern:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birthday;

當(dāng)自定義pattern后,將創(chuàng)建新的SimpleDateFormat實(shí)例來(lái)序列化日期,參見(jiàn)DateTimeSerializerBase的createContextual()方法:

public JsonSerializer createContextual(SerializerProvider serializers, BeanProperty property) throws JsonMappingException
{
  ...
  if (format.hasPattern()) {
      final Locale loc = format.hasLocale() ? format.getLocale() : serializers.getLocale();
      SimpleDateFormat df = new SimpleDateFormat(format.getPattern(), loc);
      TimeZone tz = format.hasTimeZone() ? format.getTimeZone() : serializers.getTimeZone();
      df.setTimeZone(tz);
      return withFormat(Boolean.FALSE, df);
  }
  ...
}

常用注解

不過(guò)多解釋各注解的作用,請(qǐng)看輸出結(jié)果。
示例1

import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

@JsonPropertyOrder({"firstName", "lastName"})
@JsonIgnoreProperties({"id"})
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Hero {
    private Integer id;
    // define one or more alternative names for a property during deserialization.
    @JsonAlias({"fName", "f_name"})
    private String firstName;
    private String lastName;

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new Hero(1, "Jason", "Sun")));
        System.out.println(JsonUtil.generate(new Hero(1, "Jason", null)));
        System.out.println(JsonUtil.parse("{\"fName\":\"Jason\",\"lastName\":\"Sun\"}", Hero.class).getFirstName());
    }

    public Hero() {
    }

    public Hero(Integer id, String firstName, String lastName) {
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }

    // getter and setter
}       

輸出結(jié)果:

{"firstName":"Jason","lastName":"Sun"}
{"firstName":"Jason"}
Jason

示例2

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreType;
import com.fasterxml.jackson.annotation.JsonProperty;

public class Hero {
    @JsonIgnore
    private Integer id;
    private String nickname;
    private Name name;
    @JsonProperty("mail")
    private String email;

    @JsonIgnoreType
    public static class Name {
        private String firstName;
        private String lastName;

        public Name(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        // getter and setter
    }

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new Hero(1, "chuanchuan", new Name("Jason", "Sun"), "jason@163.com")));
    }

    public Hero() {
    }

    public Hero(Integer id, String nickname, Name name, String email) {
        this.id = id;
        this.nickname = nickname;
        this.name = name;
        this.email = email;
    }

    // getter and setter
}       

輸出結(jié)果:

{"nickname":"chuanchuan","mail":"jason@163.com"}

示例3
使用@JsonValue控制整個(gè)類(lèi)序列化的結(jié)果,一個(gè)類(lèi)中最多只能含有一個(gè)@JsonValue。

import com.fasterxml.jackson.annotation.JsonValue;

public class HeroWithValue {
    private Integer id;
    @JsonValue
    private String name;
    private String email;

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new HeroWithValue(1, "Jason", "jason@163.com")));
    }

    public HeroWithValue(Integer id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // getter and setter
}

輸出結(jié)果:

"Jason"

示例4

public class Views {
    public static class Public {
    }

    public static class Internal extends Public {
    }
}
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.ObjectMapper;

public class HeroWithView {
    @JsonView(Views.Public.class)
    private int id;

    @JsonView(Views.Public.class)
    private String name;

    @JsonView(Views.Internal.class)
    private String email;

    public static void main(String[] args) throws Exception {
        HeroWithView hero = new HeroWithView(1, "Jason", "jason@163.com");

        String publicResult = new ObjectMapper().writerWithView(Views.Public.class).writeValueAsString(hero);
        String internalResult = new ObjectMapper().writerWithView(Views.Internal.class).writeValueAsString(hero);
        System.out.println(publicResult);
        System.out.println(internalResult);
    }

    public HeroWithView(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }
}

輸出結(jié)果:

{"id":1,"name":"Jason"}
{"id":1,"name":"Jason","email":"jason@163.com"}

示例5

import com.fasterxml.jackson.annotation.JsonRootName;
import com.fasterxml.jackson.annotation.JsonUnwrapped;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

@JsonRootName(value = "hero")
public class UnwrappedHero {
    private int id;
    @JsonUnwrapped
    private Name name;

    public static void main(String[] args) throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(SerializationFeature.WRAP_ROOT_VALUE);
        System.out.println(mapper.writeValueAsString(new UnwrappedHero(1, new Name("Jason", "Sun"))));
    }

    public UnwrappedHero(int id, Name name) {
        this.id = id;
        this.name = name;
    }

    public static class Name {
        private String firstName;
        private String lastName;

        public Name(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        // getter and setter
    }

    // getter and setter
}

示例6

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;

public class Zoo {
    private Animal animal;

    public Zoo(Animal animal) {
        this.animal = animal;
    }

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = Dog.class, name = "dog"),
            @JsonSubTypes.Type(value = Cat.class, name = "cat")
    })
    public static class Animal {
        private String name;

        public Animal(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    @JsonTypeName("dog")
    public static class Dog extends Animal {
        private double barkVolume;

        public Dog(String name) {
            super(name);
        }

        public double getBarkVolume() {
            return barkVolume;
        }

        public void setBarkVolume(double barkVolume) {
            this.barkVolume = barkVolume;
        }
    }

    @JsonTypeName("cat")
    public static class Cat extends Animal {
        private boolean likesCream;
        private int lives;

        public Cat(String name) {
            super(name);
        }

        public boolean isLikesCream() {
            return likesCream;
        }

        public void setLikesCream(boolean likesCream) {
            this.likesCream = likesCream;
        }

        public int getLives() {
            return lives;
        }

        public void setLives(int lives) {
            this.lives = lives;
        }
    }

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new Zoo(new Dog("lacy"))));
        System.out.println(JsonUtil.generate(new Zoo(new Cat("tom"))));
    }

    public Animal getAnimal() {
        return animal;
    }

    public void setAnimal(Animal animal) {
        this.animal = animal;
    }
}

輸出結(jié)果:

{"animal":{"type":"dog","name":"lacy","barkVolume":0.0}}
{"animal":{"type":"cat","name":"tom","likesCream":false,"lives":0}}

示例7
雙向關(guān)聯(lián)時(shí)如未做處理,會(huì)發(fā)生錯(cuò)誤:com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError),可組合使用@JsonManagedReference和@JsonBackReference。

public class Hero {
    private Integer id;
    private String name;
    @JsonManagedReference
    private List races = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Hero hero = new Hero(1, "jason");
        Race race = new Race(1, "marathon", 42.195f);
        hero.addRace(race);

        System.out.println(JsonUtil.generate(hero));
        System.out.println(JsonUtil.generate(race));
    }

    public Hero(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public void addRace(Race race) {
        races.add(race);
        race.setHero(this);
    }

    // getter and setter
}
import com.fasterxml.jackson.annotation.JsonBackReference;

public class Race {
    private Integer id;
    private String type;
    private Float distance;
    @JsonBackReference
    private Hero hero;

    public Race(Integer id, String type, Float distance) {
        this.id = id;
        this.type = type;
        this.distance = distance;
    }

    // getter and setter
}

輸出結(jié)果:

{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195}]}
{"id":1,"type":"marathon","distance":42.195}

示例8
雙向關(guān)聯(lián)的另一種解決方案,使用@JsonIdentityInfo。

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import java.util.ArrayList;
import java.util.List;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Hero {
    private Integer id;
    private String name;
    private List races = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Hero hero = new Hero(1, "jason");
        Race race = new Race(1, "marathon", 42.195f);
        hero.addRace(race);

        System.out.println(JsonUtil.generate(hero));
        System.out.println(JsonUtil.generate(race));
    }

    public Hero(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public void addRace(Race race) {
        races.add(race);
        race.setHero(this);
    }

    // getter and setter
}
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Race {
    private Integer id;
    private String type;
    private Float distance;
    private Hero hero;

    public Race(Integer id, String type, Float distance) {
        this.id = id;
        this.type = type;
        this.distance = distance;
    }

    // getter and setter
}

輸出結(jié)果:

{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195,"hero":1}]}
{"id":1,"type":"marathon","distance":42.195,"hero":{"id":1,"name":"jason","races":[1]}}

示例9
上例,如果要Race序列化結(jié)果僅含有hero id,可以組合使用@JsonIdentityInfo和@JsonIdentityReference。

import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

import java.util.ArrayList;
import java.util.List;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id", resolver = HeroIdResolver.class)
public class Hero {
    private Integer id;
    private String name;
    private List races = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        Hero hero = new Hero(1, "jason");
        Race race = new Race(1, "marathon", 42.195f);
        hero.addRace(race);

        System.out.println(JsonUtil.generate(hero));
        System.out.println(JsonUtil.generate(race));
    }

    public Hero(Integer id) {
        this.id = id;
    }

    public Hero(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public void addRace(Race race) {
        races.add(race);
        race.setHero(this);
    }

    // getter and setter
}
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Race {
    private Integer id;
    private String type;
    private Float distance;
    @JsonIdentityReference(alwaysAsId = true)
    @JsonProperty("heroId")
    private Hero hero;

    public Race(Integer id, String type, Float distance) {
        this.id = id;
        this.type = type;
        this.distance = distance;
    }

    // getter and setter
}

為了支持反序列化,需要自定義ObjectIdResolver:

import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdResolver;

public class HeroIdResolver implements ObjectIdResolver {
    @Override
    public void bindItem(ObjectIdGenerator.IdKey id, Object pojo) {

    }

    @Override
    public Object resolveId(ObjectIdGenerator.IdKey id) {
        return new Hero((Integer) id.key);
    }

    @Override
    public ObjectIdResolver newForDeserialization(Object context) {
        return new HeroIdResolver();
    }

    @Override
    public boolean canUseFor(ObjectIdResolver resolverType) {
        return resolverType.getClass() == getClass();
    }
}

輸出結(jié)果:

{"id":1,"name":"jason","races":[{"id":1,"type":"marathon","distance":42.195,"heroId":1}]}
{"id":1,"type":"marathon","distance":42.195,"heroId":1}

示例10
自定義Annotation,將多個(gè)Annotation組合起來(lái)。

import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({"name", "id", "dateCreated"})
public @interface CustomAnnotation {
}
import java.util.Date;

@CustomAnnotation
public class HeroWithCustomAnnotation {
    private Integer id;
    private String name;
    private Date dateCreated;

    public static void main(String[] args) throws Exception {
        System.out.println(JsonUtil.generate(new HeroWithCustomAnnotation(1, "Jason", null)));
    }

    public HeroWithCustomAnnotation(Integer id, String name, Date dateCreated) {
        this.id = id;
        this.name = name;
        this.dateCreated = dateCreated;
    }

    // getter and setter
}

輸出結(jié)果:

{"name":"Jason","id":1}

Spring Boot與Jackson

Spring Boot使用HttpMessageConverters處理HTTP交換中的內(nèi)容轉(zhuǎn)換。當(dāng)classpath中存在Jackson時(shí),Jackson2ObjectMapperBuilder提供默認(rèn)的Converter,源碼請(qǐng)查看HttpMessageConverters和WebMvcConfigurationSupport:
HttpMessageConverters

private List> getDefaultConverters() {
    List> converters = new ArrayList<>();
    if (ClassUtils.isPresent("org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport", null)) {
        converters.addAll(new WebMvcConfigurationSupport() {
            public List> defaultMessageConverters() {
                return super.getMessageConverters();
            }
        }.defaultMessageConverters());
    }
    else {
        converters.addAll(new RestTemplate().getMessageConverters());
    }
    reorderXmlConvertersToEnd(converters);
    return converters;
}

WebMvcConfigurationSupport

protected final void addDefaultHttpMessageConverters(List> messageConverters) {
    StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
    stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

    messageConverters.add(new ByteArrayHttpMessageConverter());
    messageConverters.add(stringHttpMessageConverter);
    messageConverters.add(new ResourceHttpMessageConverter());
    messageConverters.add(new ResourceRegionHttpMessageConverter());
    messageConverters.add(new SourceHttpMessageConverter<>());
    messageConverters.add(new AllEncompassingFormHttpMessageConverter());

    ...

    if (jackson2Present) {
        Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
        if (this.applicationContext != null) {
            builder.applicationContext(this.applicationContext);
        }
        messageConverters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }
    ...
}

Jackson2ObjectMapperBuilder創(chuàng)建ObjectMapper實(shí)例:
Jackson2ObjectMapperBuilder

public  T build() {
    ObjectMapper mapper;
    if (this.createXmlMapper) {
        mapper = (this.defaultUseWrapper != null ?
                new XmlObjectMapperInitializer().create(this.defaultUseWrapper) :
                new XmlObjectMapperInitializer().create());
    }
    else {
        mapper = (this.factory != null ? new ObjectMapper(this.factory) : new ObjectMapper());
    }
    configure(mapper);
    return (T) mapper;
}

...

private void customizeDefaultFeatures(ObjectMapper objectMapper) {
    if (!this.features.containsKey(MapperFeature.DEFAULT_VIEW_INCLUSION)) {
        configureFeature(objectMapper, MapperFeature.DEFAULT_VIEW_INCLUSION, false);
    }
    if (!this.features.containsKey(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)) {
        configureFeature(objectMapper, DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
}

默認(rèn)禁用了MapperFeature.DEFAULT_VIEW_INCLUSION、DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES。

Auto Configurationk中默認(rèn)禁用了WRITE_DATES_AS_TIMESTAMPS:
JacksonAutoConfiguration

static {
    Map featureDefaults = new HashMap<>();
    featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);
}

配置Jackson

針對(duì)ObjectMapper的六種Feature,Spring Boot都提供了相應(yīng)的配置,列表如下:

Feature(Enum)Spring Boot PropertyValues
com.fasterxml.jackson.databind.DeserializationFeature spring.jackson.deserialization.feature_name true, false
com.fasterxml.jackson.core.JsonGenerator.Feature spring.jackson.generator.feature_name true, false
com.fasterxml.jackson.databind.MapperFeature spring.jackson.mapper.feature_name true, false
com.fasterxml.jackson.core.JsonParser.Feature spring.jackson.parser.feature_name true, false
com.fasterxml.jackson.databind.SerializationFeature spring.jackson.serialization.feature_name true, false
com.fasterxml.jackson.annotation.JsonInclude.Include spring.jackson.default-property-inclusion always, non_null, non_absent, non_default, non_empty

例如,為啟用美化打印,設(shè)置spring.jackson.serialization.indent_output=true,相當(dāng)于啟用SerializationFeature.INDENT_OUTPUT,配置中忽略feature_name大小寫(xiě)。

其他的Jackson配置屬性:

  • spring.jackson.date-format= # Date format string or a fully-qualified date format class name. For instance, yyyy-MM-dd HH:mm:ss.
  • spring.jackson.joda-date-time-format= # Joda date time format string. If not configured, "date-format" is used as a fallback if it is configured with a format string.
  • spring.jackson.locale= # Locale used for formatting.
  • spring.jackson.property-naming-strategy= # One of the constants on Jackson's PropertyNamingStrategy. Can also be a fully-qualified class name of a PropertyNamingStrategy subclass.
  • spring.jackson.time-zone= # Time zone used when formatting dates. For instance, "America/Los_Angeles" or "GMT+10".

其中spring.jackson.date-format默認(rèn)值為com.fasterxml.jackson.databind.util.StdDateFormat。

@DateTimeFormat和@JsonFormat

在REST編程中,當(dāng)提交application/json的POST/PUT請(qǐng)求時(shí),JSON會(huì)通過(guò)Jackson進(jìn)行轉(zhuǎn)換。當(dāng)提交GET請(qǐng)求時(shí),如參數(shù)中包含日期,后臺(tái)代碼需要使用注解@DateTimeFormat:

@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;

兩者可以同時(shí)使用:

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date startDate;

JSON編碼

@RestController
@RequestMapping(value = "/api", produces = MediaType.APPLICATION_JSON_VALUE)
@Api(tags = {"Hello Controller"})
public class HelloController {
  ...
}

JSON MediaType為"application/json;charset=UTF-8",默認(rèn)charset為"UTF-8"。
如果遺留代碼使用了GBK編碼,我們修改produces為"application/json;charset=GBK",會(huì)生效么?根據(jù)JSON規(guī)范The JavaScript Object Notation (JSON) Data Interchange Format - Character Encoding,JSON僅支持UTF-8、UTF-16、UTF-32編碼。

查看源碼驗(yàn)證一下:
AbstractJackson2HttpMessageConverter

public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter {

    @Override
    protected void writeInternal(Object object, @Nullable Type type, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        MediaType contentType = outputMessage.getHeaders().getContentType();
        JsonEncoding encoding = getJsonEncoding(contentType);
        JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
        ...
    }

    ...

    protected JsonEncoding getJsonEncoding(@Nullable MediaType contentType) {
        if (contentType != null && contentType.getCharset() != null) {
            Charset charset = contentType.getCharset();
            for (JsonEncoding encoding : JsonEncoding.values()) {
                if (charset.name().equals(encoding.getJavaName())) {
                    return encoding;
                }
            }
        }
        return JsonEncoding.UTF8;
    }
}

JsonEncoding

public enum JsonEncoding {
    UTF8("UTF-8", false, 8), // N/A for big-endian, really
        UTF16_BE("UTF-16BE", true, 16),
        UTF16_LE("UTF-16LE", false, 16),
        UTF32_BE("UTF-32BE", true, 32),
        UTF32_LE("UTF-32LE", false, 32)
                ...
}

可以看到JsonEncoding僅包含UTF-8、UTF-16BE、UTF-16LE、UTF-32BE、UTF-32LE幾種編碼。

參考文檔

Jackson Annotation Examples


新聞標(biāo)題:SpringBoot中Jackson應(yīng)用詳解
新聞來(lái)源:http://weahome.cn/article/goodhe.html

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部