Как я могу вернуть JAX-RS свойство Java 8 LocalDateTime в качестве строки даты в стиле JavaScript?

Я создал веб-службу RESTful, используя аннотации метода JAX-RS:

@GET
@Path("/test")
@Produces(MediaType.APPLICATION_JSON)
public MyThing test()
{
    MyThing myObject = new MyThing(LocalDateTime.now());
    return myObject;
}

это работает хорошо, но я хотел бы настроить одну вещь: если возвращаемый объект Java содержит свойство нового типа Java 8 LocalDateTime, он представлен как объект JSON:

{"myDateTimeProperty":{"hour":14,"minute":32,"second":39,"year":2014,"month":"NOVEMBER","dayOfMonth":6,"dayOfWeek":"THURSDAY","dayOfYear":310,"monthValue":11,"nano":0,"chronology":{"calendarType":"iso8601","id":"ISO"}},...}

как я могу сказать JAX-RS, чтобы вернуть дату JavaScript.toJSON () - строка в стиле

{"myDateTimeProperty":"2014-11-07T15:06:36.545Z",...}
?

3 ответов


Примечание: см. обновление ниже

Я никогда не использую LocalDateTime раньше, поэтому я решил сделать некоторые испытания. Вот мои выводы:

  • Jersy 2.13 и этот поставщик (работает в коробке без дополнительной конфигурации)

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-moxy</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    
  • Джерси 2.13 с этим поставщиком (имеет поддержку аннотации JAXB - зависимость от jackson-module-JAXB-аннотации), с пользовательским адаптером

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey.version}</version>
    </dependency>
    
    public class LocalDateTimeAdapter extends XmlAdapter<String, LocalDateTime> {
        @Override
        public LocalDateTime unmarshal(String s) throws Exception {
            return LocalDateTime.parse(s);
        }
        @Override
        public String marshal(LocalDateTime dateTime) throws Exception {
            return dateTime.toString();
        }   
    }
    
    // Getter for model class
    @XmlJavaTypeAdapter(LocalDateTimeAdapter.class)
    public LocalDateTime getDateTime() {
        return dateTime;
    }
    
  • Resteasy 3.0.9 с этим провайдером (также поддерживает аннотацию JAXB-зависимость от Jackson-module-JAXB-annotations), с пользовательским адаптером (см. выше)

    <dependency>
        <groupId>org.jboss.resteasy</groupId>
        <artifactId>resteasy-jackson2-provider</artifactId>
        <version>${resteasy.version}</version>
    </dependency>
    
  • и Resteasy, и Jersey с этой зависимостью (также не работали без настраиваемой конфигурации, как и последние два - с адаптером)

    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
        <version>2.4.0</version>
    </dependency>
    

    нам нужно обязательно зарегистрировать JacksonJaxbJsonProvider


поэтому я думаю, кажется, что любой провайдер, который использует Джексона, не дайте вам результат deisred, без некоторой пользовательской конфигурации, будь то через адаптер (как показано выше) или какую-либо другую пользовательскую конфигурацию. The jersey-media-moxy провайдер не использует Джексон.


обновление

по большей части, информация выше неверна.

  • бренда не работать по умолчанию. Он работает для сериализации, просто вызывая toString(), который может или не может быть то, что вы хотите, и это не сработает, когда de-сериализации. Если вы используете MOXy, пока он не поддерживает время Java8, вам нужно будет используйте XMLAdapter

  • Джексон вам понадобится настройте поддержку времени Java8. Это относится как к Джерси, так и к RESTEasy.


Я не помню точных деталей, почему я это сделал, но я получил его работу со следующими зависимостями:

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.4.2</version>
  <scope>provided</scope>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-jsr310</artifactId>
  <version>2.4.2</version>
</dependency>

и поставщик ниже:

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
  private static final ObjectMapper om = init();

  @Override public ObjectMapper getContext(Class<?> objectType) {
    return om;
  }

  private static ObjectMapper init() {
    ObjectMapper om = new ObjectMapper();
    om.registerModule(new JavaTimeModule());
    return om;
  }
}

обратите внимание, что вы также можете играть со следующими флагами:

om.configure(WRITE_DATES_AS_TIMESTAMPS, true/false);

(фактический класс имеет больше вещей в нем, но я считаю, что это не имеет никакого отношения к этому ответу).


обновлено: работает с: <version>2.4.2</version>

когда я попробую выше:

вызвано: java.ленг.NoSuchMethodError: com.fasterxml.Джексон.тип данных.jsr310.серийный.JSR310FormattedSerializerBase.findFormatOverrides(Lcom/fasterxml/jackson/databind/SerializerProvider;Lcom/fasterxml/jackson/databind/BeanProperty;Ljava/lang/Class;)Lcom/fasterxml/jackson/annotation/JsonFormat$Value;

я получаю следующую ошибку. Любая идея plse?

<jackson.version>2.8.0</jackson.version>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
            <version>${jackson.version}</version>

package com.jobs.spring.configuration;

import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;

@Provider
@Produces(MediaType.APPLICATION_JSON)
public class JacksonContextResolver implements ContextResolver<ObjectMapper> {
    private static final ObjectMapper om = init();

    @Override
    public ObjectMapper getContext(Class<?> objectType) {
        return om;
    }

    private static ObjectMapper init() {
        ObjectMapper om = new ObjectMapper();
        om.registerModule(new JSR310Module());
        return om;
    }
}

также попытался со следующим as JSR310Module() это deprecicated в 2.8.0

om.registerModule(new JavaTimeModule());