2016-10-30 50 views
6

Przeczytałem kilka pytań z odpowiedziami tutaj w SO dotyczących serializacji i deserializacji między java.time.LocalDateTime i własności JSON, ale nie mogę sprawić, żeby to działało.Deserialize Java 8 LocalDateTime z JacksonMapper

Udało mi się skonfigurować moją aplikację Spring Boot, aby zwrócić daty w żądanym formacie (YYY-MM-dd HH:mm), ale mam problemy z akceptacją wartości w tym formacie w JSON.

Są to wszystko rzeczy, zrobiłem do tej pory:

Dodany zależność Maven dla jsr310:

<dependency> 
    <groupId>com.fasterxml.jackson.datatype</groupId> 
    <artifactId>jackson-datatype-jsr310</artifactId> 
</dependency> 

określono jsr310 w moim główne klasy:

@EntityScan(basePackageClasses = { App.class, Jsr310JpaConverters.class }) 

serializacji niepełnosprawnych jako znaczników czasu w application.properties:

spring.jackson.serialization.write_dates_as_timestamps=false 

A to moja jednostka mapowania dla datetime:

@Column(name = "start_date") 
@DateTimeFormat(iso = DateTimeFormat.ISO.TIME) 
@JsonFormat(pattern = "YYYY-MM-dd HH:mm") 
private LocalDateTime startDate; 

W mojej bazy danych, przechowywać tę datę jako znacznikiem czasu w następującym formacie: 2016-12-01T23:00:00+00:00.

Jeśli dostęp do tej jednostki za pośrednictwem kontrolera, zwraca JSON z poprawnym formatem startDate. Kiedy próbuję opublikować i deserializować go jednak, przy użyciu formatu YYYY-MM-dd HH:mm, pojawia się następujący wyjątek:

{ 
    "timestamp": "2016-10-30T14:22:25.285+0000", 
    "status": 400, 
    "error": "Bad Request", 
    "exception": "org.springframework.http.converter.HttpMessageNotReadableException", 
    "message": "Could not read document: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: [email protected]; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"]); nested exception is com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not deserialize value of type java.time.LocalDateTime from String \"2017-01-01 20:00\": Text '2017-01-01 20:00' could not be parsed: Unable to obtain LocalDateTime from TemporalAccessor: {MonthOfYear=1, WeekBasedYear[WeekFields[SUNDAY,1]]=2017, DayOfMonth=1},ISO resolved to 20:00 of type java.time.format.Parsed\n at [Source: [email protected]; line: 6, column: 16] (through reference chain: com.gigsterous.api.model.Event[\"startDate\"])", 
    "path": "/api/events" 
} 

wiem, że istnieje wiele odpowiedzi dotyczące tego tematu, ale po nich i próbuje na kilka godzin nie pomogło mnie, aby dowiedzieć się, co robię źle, więc byłbym zadowolony, gdyby ktoś mógł mi wskazać, czego mi brakuje. Dzięki za wszelkie dane na ten temat!

EDIT: Są to wszystkie klasy biorące udział w procesie:

Repozytorium:

Kontroler:

@RequestMapping(method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) 
public ResponseEntity<Event> createEvent(@RequestBody Event event) { 
     return new ResponseEntity<>(eventRepo.save(event), HttpStatus.CREATED); 
} 

Moja prośba JSON payalod:

{ 
    "name": "Test", 
    "startDate": "2017-01-01 20:00" 
} 

Przeddzień nt:

@Entity 
@Table(name = "events") 
@Getter 
@Setter 
public class Event { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "event_id") 
    private long id; 

    @Column(name = "name") 
    private String name; 

    @Column(name = "start_date") 
    @DateTimeFormat(iso = DateTimeFormat.ISO.TIME) 
    @JsonFormat(pattern = "YYYY-MM-dd HH:mm") 
    private LocalDateTime startDate; 
} 
+0

Czy możesz podzielić się resztą śladu, abyśmy wszyscy mogli sprawdzić, które klasy są zaangażowane w analizowanie wartości? Również Adnotacja DateTimeFormat wygląda na miejscu – Ivan

+0

@Ivan Dodałem wszystkie informacje do mojego pytania i zaktualizowałem śledzenie – Smajl

Odpowiedz

3

Mijana data nie jest formatem daty lokalnej w iso.

Zmiana

@Column(name = "start_date") 
@DateTimeFormat(iso = DateTimeFormatter.ISO_LOCAL_DATE_TIME) 
@JsonFormat(pattern = "YYYY-MM-dd HH:mm") 
private LocalDateTime startDate; 

i przekazać daty ciąg w formacie '2011-12-03T10: 15: 30'.

Ale jeśli nadal chcesz przekazać swój niestandardowy format, wystarczy podać odpowiedni format.

Zmiana

@Column(name = "start_date") 
@DateTimeFormat(iso = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) 
@JsonFormat(pattern = "YYYY-MM-dd HH:mm") 
private LocalDateTime startDate; 

Myślę, że problem jest @DateTimeFormat nie ma wpływu w ogóle. Podczas gdy jackson robi dewastację i nie wie nic na temat adnotacji wiosennych i nie widzę wiosennego skanowania tej adnotacji w kontekście deserializacji.

Alternatywnie można spróbować ustawić formatter podczas rejestracji modułu czasu java.

LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); 
module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer); 

Tutaj jest przypadek testowy z urządzeniem do narzucania, który działa dobrze. Może spróbować całkowicie pozbyć się tej adnotacji DateTimeFormat.

@RunWith(JUnit4.class) 
public class JacksonLocalDateTimeTest { 

    private ObjectMapper objectMapper; 

    @Before 
    public void init() { 
     JavaTimeModule module = new JavaTimeModule(); 
     LocalDateTimeDeserializer localDateTimeDeserializer = new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); 
     module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer); 
     objectMapper = Jackson2ObjectMapperBuilder.json() 
       .modules(module) 
       .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 
       .build(); 
    } 

    @Test 
    public void test() throws IOException { 
     final String json = "{ \"date\": \"2016-11-08 12:00\" }"; 
     final JsonType instance = objectMapper.readValue(json, JsonType.class); 

     assertEquals(LocalDateTime.parse("2016-11-08 12:00",DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")), instance.getDate()); 
    } 
} 


class JsonType { 
    private LocalDateTime date; 

    public LocalDateTime getDate() { 
     return date; 
    } 

    public void setDate(LocalDateTime date) { 
     this.date = date; 
    } 
} 
+1

Mam błąd z tym powiedzeniem Nie mogę przekonwertować z DateTimeFormatter na DateTimeFormat.ISO – Smajl

+0

Użyj springiveivent dla tego formatyzatora. masz dobry pomysł? – Veeram

+0

Nie ma takiej klasy o nazwie DateTimeFormatter na wiosnę. Jest tylko DateTimeFormat (wspomniałem o tym w moim pytaniu) i wypróbowałem oba formaty (2011-12-03T10: 15: 30 i 2011-12-03 10:15). Żaden z nich nie zadziałał. – Smajl

4

Użyłeś złego się sprawę do roku w kolejce:

@JsonFormat(pattern = "YYYY-MM-dd HH:mm") 

Powinno być:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm") 

Dzięki tej zmianie wszystko działa zgodnie z oczekiwaniami.

0

można zaimplementować JsonSerializer

Patrz:

Że twoja propertie w fasoli

@JsonProperty("start_date") 
@JsonFormat("YYYY-MM-dd HH:mm") 
@JsonSerialize(using = DateSerializer.class) 
private Date startDate; 

ten sposób zaimplementować klasę niestandardową

public class DateSerializer extends JsonSerializer<Date> implements ContextualSerializer<Date> { 

    private final String format; 

    private DateSerializer(final String format) { 
     this.format = format; 
    } 

    public DateSerializer() { 
     this.format = null; 
    } 

    @Override 
    public void serialize(final Date value, final JsonGenerator jgen, final SerializerProvider provider) throws IOException { 
     jgen.writeString(new SimpleDateFormat(format).format(value)); 
    } 

    @Override 
    public JsonSerializer<Date> createContextual(final SerializationConfig serializationConfig, final BeanProperty beanProperty) throws JsonMappingException { 
     final AnnotatedElement annotated = beanProperty.getMember().getAnnotated(); 
     return new DateSerializer(annotated.getAnnotation(JsonFormat.class).value()); 
    } 

} 

Spróbuj tego po wyniku post na nas.