Question

I am using FasterXML to map my objects to MongoDB

I'd like to use an expiring index, but for that, I need an ISODate field on my document.

If my java class has a Date field, it gets serialised either by a number or a string, using the DateSerializer as described here: http://wiki.fasterxml.com/JacksonFAQDateHandling

I tracked it down to this function:

/**
 * Method that will handle serialization of Date(-like) values, using
 * {@link SerializationConfig} settings to determine expected serialization
 * behavior.
 * Note: date here means "full" date, that is, date AND time, as per
 * Java convention (and not date-only values like in SQL)
 */
public final void defaultSerializeDateValue(Date date, JsonGenerator jgen)
    throws IOException, JsonProcessingException
{
    // [JACKSON-87]: Support both numeric timestamps and textual
    if (isEnabled(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)) {
        jgen.writeNumber(date.getTime());
    } else {
        jgen.writeString(_dateFormat().format(date));
    }
}

None of those two paths ends up writing a standard mongodb date type, and thus my index does not work.

Is there a way to force the java Date type to be serialised as it would be when creating the document from the mongo shell? Alternatively, can I automatically add the field via a "trigger" or something like that? (with the objective of bypassing the serializer altogether)

Was it helpful?

Solution

I have exactly the same problem with new version of FasterXML. (2.7.3). FasterXML now have a "Codec" to handle objects, beside of serializers. I resolved that issue with a serializer that invalidate the codec so the date object arrive to mongo driver without been touch.

private static class MongoDateSerializer extends JsonSerializer<Date> {

    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        TokenBuffer buffer = (TokenBuffer) jgen;
        ObjectCodec codec = buffer.getCodec();
        buffer.setCodec(null);

        buffer.writeObject(value);

        buffer.setCodec(codec);
    }
}

Look the line buffer.writeObject(value) , thats the way that old versions of FasterXML just did it.

OTHER TIPS

you can initialize the ObjectMapper with your own DateFormat, by invoke setDateFormat().

for example:

public static void main(String[] args) throws JsonGenerationException, JsonMappingException,
        IOException {
    ObjectMapper mapper = null;
    mapper = new ObjectMapper();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy~MM~dd");
    mapper.setDateFormat(sdf); // 1.8 and above
    //mapper.getSerializationConfig().setDateFormat(sdf); // for earlier versions (deprecated for 1.8+)
    Map<String, Date> data = new HashMap<>();
    data.put("Key", new Date());
    System.out.println(mapper.writeValueAsString(data));
}

note: SimpleDateFormat is not thread safe.

or you can annotated bean with JsonSerialize.

for example:

public static class User {

    private int id;

    private Date createTime;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @JsonSerialize(using = DateJsonSerializer.class)
    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

and here is DateJsonSerializer.

public class DateJsonSerializer extends JsonSerializer<Date> {

    @Override
    public void serialize(Date date, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException {
        jgen.writeString("generate ISODate yourself");
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top