Como serializar Joda DateTime com processador Jackson JSON?

118

Como faço para que Jackson serialize meu objeto Joda DateTime de acordo com um padrão simples (como "dd-MM-aaaa")?

Eu tentei:

@JsonSerialize(using=DateTimeSerializer.class)
private final DateTime date;

Eu também tentei:

ObjectMapper mapper = new ObjectMapper()
    .getSerializationConfig()
    .setDateFormat(df);

Obrigado!

Haywood Jablomey
fonte
Ambos os itens acima também devem funcionar (@JsonSerialize deve implicar que o campo deve ser serializado; e o formato de data também deve se aplicar idealmente ao Joda), então você pode desejar registrar um bug do Jira em jira.codehaus.org/browse/JACKSON .
StaxMan,
Percebo que essa pergunta é de um tempo atrás, mas para referência futura, objectMapper.getSerializationConfig (). SetDateFormat (df) agora está obsoleto. objectMapper.setDateFormat (df) agora é sugerido.
Patrick,
Consulte também stackoverflow.com/questions/27952472/…
Raedwald

Respostas:

146

Isso se tornou muito fácil com Jackson 2.0 e o módulo Joda.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());

Dependência de Maven:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.1.1</version>
</dependency>  

Código e documentação: https://github.com/FasterXML/jackson-datatype-joda

Binários: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/

Kimble
fonte
13
Você poderia expandir isso, por favor? Para onde vai esse código e como a instância ObjectMapper é usada?
Paul
Você deve fazer perguntas específicas sobre o uso da API de Jackson e Maven. Para onde vai o código depende se você usa alguma estrutura / como inicializa seu aplicativo.
Kimble
4
quando adiciono que obtenho o erro de compilação "tipos incompatíveis: o JodaModule não pode ser convertido em módulo" - o método espera um org.codehaus.jackson.map.Module, mas o JodaModule não tem isso em sua hierarquia, então como isso poderia funcionar?
Martin Charlesworth
4
Promissor, mas atualmente quase inútil, pois não podemos especificar o formato de data para analisar :(
Vincent Mimoun-Prat
10
Você precisa desabilitar a serialização como timestamps objectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
MarekM
74

No objeto que você está mapeando:

@JsonSerialize(using = CustomDateSerializer.class)
public DateTime getDate() { ... }

Em CustomDateSerializer:

public class CustomDateSerializer extends JsonSerializer<DateTime> {

    private static DateTimeFormatter formatter = 
        DateTimeFormat.forPattern("dd-MM-yyyy");

    @Override
    public void serialize(DateTime value, JsonGenerator gen, 
                          SerializerProvider arg2)
        throws IOException, JsonProcessingException {

        gen.writeString(formatter.print(value));
    }
}
Rusty Kuntz
fonte
4
Como registrar CustomDateSerializer na primavera mvc 3?
digz6666 de
1
Não sei sobre Spring MVC3, mas você pode adicionar um serializador personalizado ao objeto mapeador Jackson. Veja esta entrada em Jackson. Você precisa criar um módulo simples para esse SimpleModule isoDateTimeModule = new SimpleModule ("ISODateTimeModule", new Version (1, 0, 0, null)); isoDateTimeModule.addSerializer (new JsonISODateTimeFormatSerializer ()); mapper.registerModule (isoDateTimeModule);
Guillaume Belrose
1
@ digz6666 veja minha resposta aqui para Spring MVC 3: stackoverflow.com/questions/7854030/…
Aram Kocharyan
Nota - certifique-se de usar as classes acima de em org.codehaus.jacksonvez de com.fasterxml.jackson.core. Usar o segundo pacote não funcionou para mim. Na verdade, meu aplicativo de Jersey nem mesmo respeitou a @JsonSerializedanotação.
Kevin Meredith
A resposta funcionou para mim. Mas isso exigiria essa anotação em todos os campos. Existe alguma configuração global para isso que funciona com Jackson?
Taher de
26

Como @Kimble disse, com Jackson 2, usar a formatação padrão é muito fácil; basta se cadastrar JodaModuleno seu ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());

Para serialização / desserialização customizada de DateTime, você precisa implementar seu próprio StdScalarSerializere StdScalarDeserializer; é muito complicado, mas de qualquer maneira.

Por exemplo, aqui está um DateTimeserializador que usa ISODateFormatcom o fuso horário UTC:

public class DateTimeSerializer extends StdScalarSerializer<DateTime> {

    public DateTimeSerializer() {
        super(DateTime.class);
    }

    @Override
    public void serialize(DateTime dateTime,
                          JsonGenerator jsonGenerator,
                          SerializerProvider provider) throws IOException, JsonGenerationException {
        String dateTimeAsString = ISODateTimeFormat.withZoneUTC().print(dateTime);
        jsonGenerator.writeString(dateTimeAsString);
    }
}

E o desserializador correspondente:

public class DateTimeDesrializer extends StdScalarDeserializer<DateTime> {

    public DateTimeDesrializer() {
        super(DateTime.class);
    }

    @Override
    public DateTime deserialize(JsonParser jsonParser,
                                DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        try {
            JsonToken currentToken = jsonParser.getCurrentToken();
            if (currentToken == JsonToken.VALUE_STRING) {
                String dateTimeAsString = jsonParser.getText().trim();
                return ISODateTimeFormat.withZoneUTC().parseDateTime(dateTimeAsString);
            }
        } finally {
            throw deserializationContext.mappingException(getValueClass());
        }
    }

Em seguida, vincule-os com um módulo:

public class DateTimeModule extends SimpleModule {

    public DateTimeModule() {
        super();
        addSerializer(DateTime.class, new DateTimeSerializer());
        addDeserializer(DateTime.class, new DateTimeDeserializer());
    }
}

Em seguida, registre o módulo em ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new DateTimeModule());
oggmonster
fonte
o objeto DatatIme deserilazed está no fuso horário UTC ou então o fuso horário do navegador me ajude
user3354457
Isso registra o mapeador (e os módulos) globalmente?
raffian
16

A solução fácil

Encontrei um problema semelhante e minha solução é muito mais clara do que a acima.

Eu simplesmente usei o padrão na @JsonFormat anotação

Basicamente, minha classe tem um DateTimecampo, então coloco uma anotação ao redor do getter:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public DateTime getDate() {
    return date;
}

Eu serializo a classe com ObjectMapper

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JodaModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    ObjectWriter ow = mapper.writer();
    try {
        String logStr = ow.writeValueAsString(log);
        outLogger.info(logStr);
    } catch (IOException e) {
        logger.warn("JSON mapping exception", e);
    }

Usamos Jackson 2.5.4

Atais
fonte
15

https://stackoverflow.com/a/10835114/1113510

Embora você possa colocar uma anotação para cada campo de data, é melhor fazer uma configuração global para seu mapeador de objetos. Se você usa jackson, pode configurar sua mola da seguinte maneira:

<bean id="jacksonObjectMapper" class="com.company.CustomObjectMapper" />

<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
    factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" >
</bean>

Para CustomObjectMapper:

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        super();
        configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        setDateFormat(new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)"));
    }
}

Claro, SimpleDateFormat pode usar qualquer formato de que você precisa.

Moesio
fonte
4
setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));fez o truque para mim, thx
Konsumierer
8

Enquanto isso, Jackson registra o módulo Joda automaticamente quando o JodaModule está no caminho de classe. Acabei de adicionar jackson-datatype-joda ao Maven e funcionou instantaneamente.

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.8.7</version>
</dependency>

Saída JSON:

{"created" : "2017-03-28T05:59:27.258Z"}
Stephan
fonte
6

Para aqueles com Spring Boot, você deve adicionar o módulo ao seu contexto e ele será adicionado à sua configuração assim.

@Bean
public Module jodaTimeModule() {
    return new JodaModule();
}

E se você quiser usar o novo módulo de tempo java8 jsr-310.

@Bean
public Module jodaTimeModule() {
    return new JavaTimeModule();
}
Jgeerts
fonte
3

Parece que para Jackson 1.9.12 não existe essa possibilidade por padrão, devido a:

public final static class DateTimeSerializer
    extends JodaSerializer<DateTime>
{
    public DateTimeSerializer() { super(DateTime.class); }

    @Override
    public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonGenerationException
    {
        if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) {
            jgen.writeNumber(value.getMillis());
        } else {
            jgen.writeString(value.toString());
        }
    }

    @Override
    public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint)
    {
        return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)
                ? "number" : "string", true);
    }
}

Esta classe serializa os dados usando o método toString () do Joda DateTime.

A abordagem proposta por Rusty Kuntz funciona perfeitamente para o meu caso.

Ydrozhdzhal
fonte
Você ainda pode registrar o serializador e o desserializador customizados e eles terão precedência sobre a implementação padrão.
StaxMan
2

Estou usando Java 8 e isso funcionou para mim.

Adicione a dependência de pom.xml

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

e adicionar JodaModule em seu ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
Luciana campello
fonte