Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson custom date serializer

I need to set format for class' date serialization. I have the version of Jackson, which doesn't have @JsonFormat. That's Why I wrote custom class:

public class CDJsonDateSerializer extends JsonSerializer<Date>{

@Override
public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException {
    SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");
    String dateString = dateFormat.format(date);
    jsonGenerator.writeString(dateString);
}

}

And used it:

@JsonSerialize(using = CDJsonDateSerializer.class)
private Date startDate;

But, I have another fields which have different date's formats and I don't want to create another classes for serialization. Can I add all needed formats like constants to CDJsonDateSerializer class and set needed format with annotation @JsonSerialize ? Something like this:

@JsonSerialize(using = CDJsonDateSerializer.class, CDJsonDateSerializer.FIRST_FORMAT).

AFTER THE ANSWER BELOW:

It works after some corrections. I've changed the way of getting annotation in createContextual method:

@Override
public JsonSerializer createContextual(SerializationConfig serializationConfig, BeanProperty beanProperty) {
    return new CustomDateSerializer(beanProperty.getAnnotation(JsonDateFormat.class).value());
}

And I've added @JacksonAnnotation to my created new annotation JsonDateFormat:

@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotation
public @interface JsonDateFormat {
   String value();
}
like image 982
Alexander Kuzmenko Avatar asked Dec 02 '14 11:12

Alexander Kuzmenko


1 Answers

If you cannot use @JsonFormat from Jackson 2, I'd recommend you to introduce your own custom annotation which will contain the format field. Your serailizer should then implement the ContextualSerializer interface to get access to the annotation value.

Here is an example for Jackson 1.9.X:

public class JacksonDateFormat {
    @Retention(RetentionPolicy.RUNTIME)
    public static @interface MyJsonFormat {
        String value();
    }

    public static class Bean {
        @MyJsonFormat("dd.MM.yyyy") @JsonSerialize(using = MyDateSerializer.class)
        public final Date date1;

        @MyJsonFormat("yyyy-MM-dd") @JsonSerialize(using = MyDateSerializer.class)
        public final Date date2;

        public Bean(final Date date1, final Date date2) {
            this.date1 = date1;
            this.date2 = date2;
        }
    }

    public static class MyDateSerializer extends JsonSerializer<Date>
            implements ContextualSerializer {
        private final String format;

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

        public MyDateSerializer() {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 createContextual(
                final SerializationConfig serializationConfig, final BeanProperty beanProperty)
                throws JsonMappingException {
            final AnnotatedElement annotated = beanProperty.getMember().getAnnotated();
            return new MyDateSerializer(annotated.getAnnotation(MyJsonFormat.class).value());
        }
    }

    public static void main(String[] args) throws IOException {
        final ObjectMapper mapper = new ObjectMapper();
        final Bean value = new Bean(new Date(), new Date());
        System.out.println(mapper
                        .writerWithDefaultPrettyPrinter()
                        .writeValueAsString(value));
    }
}

Output:

{
  "date1" : "02.12.2014",
  "date2" : "2014-12-02"
}

If you have access to the ObjectMapper you can register your custom serializer for all the Date types, so you want longer need to put @JsonSerialize annotation.

Here is an example:

final ObjectMapper mapper = new ObjectMapper();
final SimpleModule module = new SimpleModule("", Version.unknownVersion());
module.addSerializer(Date.class, new MyDateSerializer(null));
mapper.registerModule(module);
like image 174
Alexey Gavrilov Avatar answered Sep 22 '22 15:09

Alexey Gavrilov