Джерси + jackson JSON формат даты формат – как изменить формат или использовать пользовательские JacksonJsonProvider

Я использую Jersey + Jackson для предоставления уровня сервиса REST JSON для моего приложения. У меня проблема в том, что формат сериализации по умолчанию выглядит так:

"CreationDate":1292236718456 

Сначала я думал, что это timestamp UNIX … но это слишком долго для этого. У моей клиентской JS-библиотеки есть проблемы, десериализирующие этот формат (он поддерживает кучу разных форматов дат, но не этот, я полагаю). Я хочу изменить формат, чтобы он мог потребляться моей библиотекой (например, по ISO). Как мне это сделать … Я нашел fragment кода, который мог бы помочь, но … где я могу это выразить, поскольку я не контролирую экземпляр Jackson serializer (Джерси делает)?

 objectMapper.configure( SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); 

Я также нашел этот код для пользовательского JacksonJsonProvider – вопрос в том, .. как я могу использовать все мои classы POJO?

 @Provider public class MessageBodyWriterJSON extends JacksonJsonProvider { private static final String DF = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"; @Override public boolean isWriteable(Class arg0, Type arg1, Annotation[] arg2, MediaType arg3) { return super.isWriteable(arg0, arg1, arg2, arg3); } @Override public void writeTo(Object target, Class arg1, Type arg2, Annotation[] arg3, MediaType arg4, MultivaluedMap arg5, OutputStream outputStream) throws IOException, WebApplicationException { SimpleDateFormat sdf=new SimpleDateFormat(DF); ObjectMapper om = new ObjectMapper(); om.getDeserializationConfig().setDateFormat(sdf); om.getSerializationConfig().setDateFormat(sdf); try { om.writeValue(outputStream, target); } catch (JsonGenerationException e) { throw e; } catch (JsonMappingException e) { throw e; } catch (IOException e) { throw e; } } } 

Для чего это стоит, это число является стандартной меткой времени Java (используется classами JDK); Unix хранит секунды, миллисекунды Java, поэтому это бит больше.

Я хотел бы надеяться, что есть некоторые документы о том, как вводить ObjectMapper в Джерси (он должен следовать обычному способу вставить предоставленный объект). Но в качестве альтернативы вы можете переопределить JacksonJaxRsProvider, чтобы указать / настроить ObjectMapper и зарегистрировать это; это то, что делает сам Джерси, и есть несколько способов сделать это.

Мне удалось сделать это в Resteasy «JAX-RS way», поэтому он должен работать над каждой совместимой реализацией, такой как Jersey (недавно успешно протестированной на JEE7-сервере Wildfly 8), просто потребовалось несколько изменений в части jacksonа, потому что они изменили несколько API).

Вы должны определить ContextResolver (проверьте, что Produces содержит правильный тип содержимого):

 import javax.ws.rs.ext.ContextResolver; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.DeserializationConfig; import javax.ws.rs.ext.Provider; import javax.ws.rs.Produces; import java.text.SimpleDateFormat; @Provider @Produces("application/json") public class JacksonConfigurator implements ContextResolver { private ObjectMapper mapper = new ObjectMapper(); public JacksonConfigurator() { SerializationConfig serConfig = mapper.getSerializationConfig(); serConfig.setDateFormat(new SimpleDateFormat()); DeserializationConfig deserializationConfig = mapper.getDeserializationConfig(); deserializationConfig.setDateFormat(new SimpleDateFormat()); mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); } @Override public ObjectMapper getContext(Class arg0) { return mapper; } } 

Затем вы должны вернуть вновь созданный class в свой javax.ws.rs.core.Application getClasses

 import javax.ws.rs.core.Application; public class RestApplication extends Application { @Override public Set> getClasses() { Set> classes = new HashSet>(); // your classes here classes.add(JacksonConfigurator.class); return classes; } } 

таким образом, вся операция, выполняемая через джексон, предоставляется ObjectMapper по вашему выбору.

EDIT: Недавно я выяснил, что использование RestEasy 2.0.1 (и, следовательно, Jackson 1.5.3) вызывает странное поведение, если вы решите расширить JacksonConfigurator, чтобы добавить пользовательские сопоставления.

 import javax.ws.rs.core.MediaType; @Provider @Produces(MediaType.APPLICATION_JSON) public class MyJacksonConfigurator extends JacksonConfigurator 

Если вы просто сделаете это (и, конечно же, добавите расширенный class в RestApplication), используется обработчик родительского classа, то есть вы потеряете пользовательские сопоставления. Чтобы сделать это правильно, я должен был сделать что-то, что мне кажется бесполезным:

 public class MyJacksonConfigurator extends JacksonConfigurator implements ContextResolver 

Чтобы настроить собственный ObjectMapper, вам нужно ввести свой собственный class, который реализует ContextResolver

Точно, как получить майку, чтобы забрать это, зависит от вашей МОК (весна, указ). Я использую весну, и мой class выглядит примерно так:

 import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig.Feature; import org.codehaus.jackson.map.deser.CustomDeserializerFactory; import org.codehaus.jackson.map.deser.StdDeserializerProvider; import org.codehaus.jackson.map.ser.CustomSerializerFactory; import org.springframework.stereotype.Component; // tell spring to look for this. @Component // tell spring it's a provider (type is determined by the implements) @Provider public class ObjectMapperProvider implements ContextResolver { @Override public ObjectMapper getContext(Class type) { // create the objectMapper. ObjectMapper objectMapper = new ObjectMapper(); // configure the object mapper here, eg. objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); return objectMapper; } } 

У меня была такая же проблема (с использованием Jersey + Jackson + Json), клиент отправил дату, но она была изменена на сервере, когда данные были отображены в объект.

Я пошел по другому подходу, чтобы решить эту проблему, прочитав эту ссылку: http://blog.bdoughan.com/2010/07/xmladapter-jaxbs-secret-weapon.html , когда я понял, что полученная дата была TimeStamp (тот же как Адрин в своем вопросе: "creationDate":1292236718456 )

В моем classе VO я добавил эту аннотацию к атрибуту @XmlJavaTypeAdapter а также реализовал внутренний class с расширенным XmlAdapter :

 @XmlRootElement public class MyClassVO { ... @XmlJavaTypeAdapter(DateFormatterAdapter.class) Date creationDate; ... private static class DateFormatterAdapter extends XmlAdapter { @Override public Date unmarshal(final String v) throws Exception { Timestamp stamp = new Timestamp(new Long(v)); Date date = new Date(stamp.getTime()); return date; } } 

Надеюсь, это тоже поможет вам.

Если вы решили работать с объектами Joda DateTime на своем сервере и хотите сериализоваться на ISO8601, вы можете использовать JodaModule от Jackson . Вы можете зарегистрировать Поставщик Джерси следующим образом:

 import javax.ws.rs.ext.ContextResolver; import javax.ws.rs.ext.Provider; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.joda.JodaModule; @Provider public class MyObjectMapperProvider implements ContextResolver { final ObjectMapper objectMapper; public MyObjectMapperProvider() { objectMapper = new ObjectMapper(); /* Register JodaModule to handle Joda DateTime Objects. */ objectMapper.registerModule(new JodaModule()); /* We want dates to be treated as ISO8601 not timestamps. */ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); } @Override public ObjectMapper getContext(Class arg0) { return objectMapper; } } 

Более подробная информация доступна на веб-сайте Джерси .

Ниже код работал для меня – JAX-RS 1.1, Jersy 1.8

 import java.text.SimpleDateFormat; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.Provider; import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion; @Provider @Produces(MediaType.APPLICATION_JSON) public class JsonProvider extends JacksonJaxbJsonProvider { private static final ObjectMapper objectMapper = new ObjectMapper(); static { // allow only non-null fields to be serialized objectMapper.getSerializationConfig().setSerializationInclusion(Inclusion.NON_NULL); SerializationConfig serConfig = objectMapper.getSerializationConfig(); serConfig.setDateFormat(new SimpleDateFormat()); DeserializationConfig deserializationConfig = objectMapper.getDeserializationConfig(); deserializationConfig.setDateFormat(new SimpleDateFormat()); objectMapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); } public JsonProvider() { super.setMapper(objectMapper); } } 

Перезапишите MessageBodyWriterJSON с помощью этого

 import javax.ws.rs.core.MediaType; import javax.ws.rs.ext.Provider; import org.codehaus.jackson.jaxrs.JacksonJsonProvider; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; @Provider public class MessageBodyWriterJSON extends JacksonJsonProvider { public MessageBodyWriterJSON (){ } @Override public ObjectMapper locateMapper(Class type, MediaType mediaType) { ObjectMapper mapper = super.locateMapper(type, mediaType); //DateTime in ISO format "2012-04-07T17:00:00.000+0000" instead of 'long' format mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false); return mapper; } } 

json-io ( https://github.com/jdereg/json-io ) – это полная библиотека Java для / из библиотеки сериализации JSON. Когда вы используете его для записи строки JSON, вы можете указать, как отформатировать даты. По умолчанию даты выписываются так долго (как указано выше, с миллисекунд с 1 января 1970 г.). Тем не менее, вы можете дать ему формат String или Java DateFormatter и указать даты, записанные в любом формате.

  • Использование jQuery для захвата содержимого из iframe CKEditor
  • JSON.Net Обнаружен собственный цикл привязки
  • В чем разница между привязкой лямбды и метода на уровне выполнения?
  • Как сериализовать объект в CSV-файл?
  • jQuery serializeArray не включает кнопку отправки, которая была нажата
  • Как десериализовать объект JObject для .NET
  • Сериализация типа Json.Net с полиморфным дочерним объектом
  • Можно ли выполнять бинарную сериализацию .NET в случае, если у вас нет исходного кода classа?
  • Deserialize специфическое перечисление в system.enum в Json.Net
  • Стандартный способ сериализации JSON для строки запроса?
  • Jackson ObjectMapper - указать порядок сортировки свойств объекта
  • Давайте будем гением компьютера.