Джерси + 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?
- Информация о сериализации типов кеша Json.NET?
- Почему java.util.Optional не является Serializable, как сериализовать объект с такими полями
- C # JSON.NET - десериализация ответа, использующего необычную структуру данных
- jackson не десериализует общий список, который он сериализовал
- Deserialize JSON в динамический объект C #?
@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: объект для байта и байт для конвертера объектов (для Tokyo Cabinet)
- Как можно полиморфная десериализация Json String с использованием Java и библиотеки Jackson?
- Ошибка JSON.NET Локальный цикл привязки для типа
- Как сериализовать словарь как часть его родительского объекта с помощью Json.Net
- JSON.Net выдает StackOverflowException при использовании
- Как десериализовать объект JObject для .NET
- gwt - Использование списка в вызове RPC?
- Служба WCF Максимальная квота длины массива (16384) превышена
Для чего это стоит, это число является стандартной меткой времени 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 и указать даты, записанные в любом формате.