2017-12-21 3 views
0

Beim Erstellen eines REST-Dienstes mit Spring Boot, der eine JSON-Nutzlast zurückgibt, wird Java 8 LocalDateTime serialisiert. Wo wird die Formatzeichenfolge (d. H. Das Muster) definiert, die (vermutlich) Jackson anwendet, wenn das Objekt zu einer Zeichenfolge gereiht wird, und wo finde ich die Standardkonfiguration in Spring Boot, die dieses Format anwendet (d. H. Setzt den Formatierer)?Wo definiert Spring Boot sein Standard-JSON-Datum (d. H. LocalDateTime) -Format?

(NB: Ich kann ein formatierte Datum sehen, nicht ein Zeitstempel, in der Nutzlast.)

+2

Ein LocalDateTime ist kein Zeitstempel, daher ist es ganz normal, dass Sie keinen Zeitstempel sehen. Das heißt, die Dokumentation beantwortet Ihre Frage: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-customize-the-jackson-objectmapper –

+0

Die Dokumente weisen mich auf ['Jackson2ObjectMapperBuilder '] (http://grepcode.com/file/repo1.maven.org/maven2/org.springframework/spring-web/4.1.1.RELEASE/org/springframework/http/converter/json/Jackson2ObjectMapperBuilder.java#460), die wiederum auf ['JSR310Module'] verweist (http://grepcode.com/file/repo1.maven.org/maven2/com.fasterxml.jackson.datatype/jackson-datatype-jsr310/2.4.4/com /fasterxml/jackson/datatype/jsr310/JSR310Module.java#129) und über ... – Christian

+0

... ['LocalDateTimeSerializer'] (http://grepcode.com/file/repo1.maven.org/maven2/com. fasterxml.jackson.datatype/jackson-datentype-jsr310/2.4.4/com/fullyxml/jackson/datentype/jsr310/ser/LocalDateTimeSerializer.java # 69) schließlich zu ['LocalDateTime :: toString'] (http: // grepcode .com/datei/repository.grepcode.com/java/root/jdk/openjdk/8u40-b 25/java/time/LocalDateTime.java # 1965). Meine 'LocalDateTime' ist auf' 1776-07-04T12: 29Z' gesetzt, trotzdem bekomme ich '1776-07-04T12: 29: 00Z'. Dokumente sagen "Das verwendete Format ist das kürzeste ... wo die weggelassenen Teile implizit Null sind": 'uuuu-MM-dd'T'HH: mm'. Warum bekomme ich ': 00' zurück? – Christian

Antwort

0

Jackson2ObjectMapperBuilder führt ziemlich knifflige Logik in registerWellKnownModulesIfAvailable Methode für mehrere Module zu registrieren. Insbesondere für Java 8 Zeit:

// Java 8 java.time package present? 
if (ClassUtils.isPresent("java.time.LocalDate", this.moduleClassLoader)) { 
    try { 
     Class<? extends Module> javaTimeModule = (Class<? extends Module>) 
       ClassUtils.forName("com.fasterxml.jackson.datatype.jsr310.JavaTimeModule", this.moduleClassLoader); 
     objectMapper.registerModule(BeanUtils.instantiateClass(javaTimeModule)); 
    } 
    catch (ClassNotFoundException ex) { 
     // jackson-datatype-jsr310 not available 
    } 
} 

Also, wenn Sie Ihre Anwendung auf jackson-datatype-jsr310 Modul Feder hängt wird es still registrieren. Als Ergebnis haben Sie dedizierte Serializer/Deserializer für Java-Zeittypen aus diesem Modul. Sie sind interessant in LocalDateTimeSerializer. Wie Sie sehen können, hängt die Serialisierungslogik von useTimestamp ab, die in Ihrem Fall false zurückgibt, so dass wir zu else verzweigen. Standardmäßig ist _formatter null und _defaultFormatter() wird verwendet, was DateTimeFormatter.ISO_LOCAL_DATE_TIME ist. Sie können dieses Verhalten problemlos aktualisieren, indem Sie ein benutzerdefiniertes Formatierungsprogramm bereitstellen, wenn Sie das Datum als Zeichenfolge serialisieren oder die Serialisierungslogik von if verwenden möchten, indem Sie die Methode true von useTimestamp zurückgeben.

@Override 
public void serialize(LocalDateTime value, JsonGenerator g, SerializerProvider provider) 
    throws IOException 
{ 
    if (useTimestamp(provider)) { 
     g.writeStartArray(); 
     g.writeNumber(value.getYear()); 
     g.writeNumber(value.getMonthValue()); 
     g.writeNumber(value.getDayOfMonth()); 
     g.writeNumber(value.getHour()); 
     g.writeNumber(value.getMinute()); 
     if (value.getSecond() > 0 || value.getNano() > 0) { 
      g.writeNumber(value.getSecond()); 
      if(value.getNano() > 0) { 
       if (provider.isEnabled(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS)) 
        g.writeNumber(value.getNano()); 
       else 
        g.writeNumber(value.get(ChronoField.MILLI_OF_SECOND)); 
      } 
     } 
     g.writeEndArray(); 
    } else { 
     DateTimeFormatter dtf = _formatter; 
     if (dtf == null) { 
      dtf = _defaultFormatter(); 
     } 
     g.writeString(value.format(dtf)); 
    } 
} 

// since 2.7: TODO in 2.8; change to use per-type defaulting 
protected DateTimeFormatter _defaultFormatter() { 
    return DateTimeFormatter.ISO_LOCAL_DATE_TIME; 
} 

protected boolean useTimestamp(SerializerProvider provider) { 
    if (_useTimestamp != null) { 
     return _useTimestamp.booleanValue(); 
    } 
    // assume that explicit formatter definition implies use of textual format 
    if (_formatter != null) { 
     return false; 
    } 
    return provider.isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 
} 
Verwandte Themen