get jackson object mapper to support dates as elasticsearch expects them
This commit is contained in:
parent
58319b1113
commit
baaac70da5
|
@ -55,7 +55,7 @@ public class JacksonTypesBenchmark {
|
|||
public JacksonTypesBenchmark(String jsonString) throws IOException {
|
||||
Preconditions.checkNotNull(jsonString, "jsonString must have a value");
|
||||
this.jsonString = jsonString;
|
||||
this.objectMapper = newObjectMapper();
|
||||
this.objectMapper = defaultObjectMapper();
|
||||
this.factor = 10;
|
||||
this.cycles = 10000;
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ public class JsonDateFieldMapper extends JsonNumberFieldMapper<Long> {
|
|||
float boost, boolean omitNorms, boolean omitTermFreqAndPositions,
|
||||
String nullValue) {
|
||||
super(names, precisionStep, index, store, boost, omitNorms, omitTermFreqAndPositions,
|
||||
new NamedAnalyzer("_date/" + precisionStep, new NumericDateAnalyzer(precisionStep, dateTimeFormatter.formatter())),
|
||||
new NamedAnalyzer("_date/max", new NumericDateAnalyzer(Integer.MAX_VALUE, dateTimeFormatter.formatter())));
|
||||
new NamedAnalyzer("_date/" + precisionStep, new NumericDateAnalyzer(precisionStep, dateTimeFormatter.parser())),
|
||||
new NamedAnalyzer("_date/max", new NumericDateAnalyzer(Integer.MAX_VALUE, dateTimeFormatter.parser())));
|
||||
this.dateTimeFormatter = dateTimeFormatter;
|
||||
this.nullValue = nullValue;
|
||||
}
|
||||
|
@ -102,11 +102,11 @@ public class JsonDateFieldMapper extends JsonNumberFieldMapper<Long> {
|
|||
}
|
||||
|
||||
@Override public String valueAsString(Fieldable field) {
|
||||
return dateTimeFormatter.formatter().print(value(field));
|
||||
return dateTimeFormatter.printer().print(value(field));
|
||||
}
|
||||
|
||||
@Override public String indexedValue(String value) {
|
||||
return NumericUtils.longToPrefixCoded(dateTimeFormatter.formatter().parseMillis(value));
|
||||
return NumericUtils.longToPrefixCoded(dateTimeFormatter.parser().parseMillis(value));
|
||||
}
|
||||
|
||||
@Override public String indexedValue(Long value) {
|
||||
|
@ -115,15 +115,15 @@ public class JsonDateFieldMapper extends JsonNumberFieldMapper<Long> {
|
|||
|
||||
@Override public Query rangeQuery(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
|
||||
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
|
||||
lowerTerm == null ? null : dateTimeFormatter.formatter().parseMillis(lowerTerm),
|
||||
upperTerm == null ? null : dateTimeFormatter.formatter().parseMillis(upperTerm),
|
||||
lowerTerm == null ? null : dateTimeFormatter.parser().parseMillis(lowerTerm),
|
||||
upperTerm == null ? null : dateTimeFormatter.parser().parseMillis(upperTerm),
|
||||
includeLower, includeUpper);
|
||||
}
|
||||
|
||||
@Override public Filter rangeFilter(String lowerTerm, String upperTerm, boolean includeLower, boolean includeUpper) {
|
||||
return NumericRangeFilter.newLongRange(names.indexName(), precisionStep,
|
||||
lowerTerm == null ? null : dateTimeFormatter.formatter().parseMillis(lowerTerm),
|
||||
upperTerm == null ? null : dateTimeFormatter.formatter().parseMillis(upperTerm),
|
||||
lowerTerm == null ? null : dateTimeFormatter.parser().parseMillis(lowerTerm),
|
||||
upperTerm == null ? null : dateTimeFormatter.parser().parseMillis(upperTerm),
|
||||
includeLower, includeUpper);
|
||||
}
|
||||
|
||||
|
@ -137,7 +137,7 @@ public class JsonDateFieldMapper extends JsonNumberFieldMapper<Long> {
|
|||
if (dateAsString == null) {
|
||||
return null;
|
||||
}
|
||||
long value = dateTimeFormatter.formatter().parseMillis(dateAsString);
|
||||
long value = dateTimeFormatter.parser().parseMillis(dateAsString);
|
||||
Field field = null;
|
||||
if (stored()) {
|
||||
field = new Field(names.indexName(), Numbers.longToBytes(value), store);
|
||||
|
|
|
@ -310,7 +310,7 @@ public class JsonObjectMapper implements JsonMapper {
|
|||
boolean isDate = false;
|
||||
for (FormatDateTimeFormatter dateTimeFormatter : dateTimeFormatters) {
|
||||
try {
|
||||
dateTimeFormatter.formatter().parseMillis(jsonContext.jp().getText());
|
||||
dateTimeFormatter.parser().parseMillis(jsonContext.jp().getText());
|
||||
mapper = dateField(currentFieldName).dateTimeFormatter(dateTimeFormatter).build(builderContext);
|
||||
isDate = true;
|
||||
break;
|
||||
|
|
|
@ -51,7 +51,7 @@ public class RestMainAction extends BaseRestHandler {
|
|||
JsonNode rootNode;
|
||||
int quotesSize;
|
||||
try {
|
||||
rootNode = Jackson.newObjectMapper().readValue(Classes.getDefaultClassLoader().getResourceAsStream("org/elasticsearch/rest/action/main/quotes.json"), JsonNode.class);
|
||||
rootNode = Jackson.defaultObjectMapper().readValue(Classes.getDefaultClassLoader().getResourceAsStream("org/elasticsearch/rest/action/main/quotes.json"), JsonNode.class);
|
||||
ArrayNode arrayNode = (ArrayNode) rootNode.get("quotes");
|
||||
quotesSize = Iterators.size(arrayNode.getElements());
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -33,18 +33,29 @@ public class FormatDateTimeFormatter {
|
|||
|
||||
private final String format;
|
||||
|
||||
private final DateTimeFormatter formatter;
|
||||
private final DateTimeFormatter parser;
|
||||
|
||||
public FormatDateTimeFormatter(String format, DateTimeFormatter formatter) {
|
||||
private final DateTimeFormatter printer;
|
||||
|
||||
public FormatDateTimeFormatter(String format, DateTimeFormatter parser) {
|
||||
this(format, parser, parser);
|
||||
}
|
||||
|
||||
public FormatDateTimeFormatter(String format, DateTimeFormatter parser, DateTimeFormatter printer) {
|
||||
this.format = format;
|
||||
this.formatter = formatter;
|
||||
this.parser = parser;
|
||||
this.printer = printer;
|
||||
}
|
||||
|
||||
public String format() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public DateTimeFormatter formatter() {
|
||||
return formatter;
|
||||
public DateTimeFormatter parser() {
|
||||
return parser;
|
||||
}
|
||||
|
||||
public DateTimeFormatter printer() {
|
||||
return this.printer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,7 +73,10 @@ public class Joda {
|
|||
} else if ("dateHourMinuteSecondMillis".equals(input)) {
|
||||
formatter = ISODateTimeFormat.dateHourMinuteSecondMillis();
|
||||
} else if ("dateOptionalTime".equals(input)) {
|
||||
formatter = ISODateTimeFormat.dateOptionalTimeParser();
|
||||
// in this case, we have a separate parser and printer since the dataOptionalTimeParser can't print
|
||||
return new FormatDateTimeFormatter(input,
|
||||
ISODateTimeFormat.dateOptionalTimeParser().withZone(DateTimeZone.UTC),
|
||||
ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC));
|
||||
} else if ("dateTime".equals(input)) {
|
||||
formatter = ISODateTimeFormat.dateTime();
|
||||
} else if ("dateTimeNoMillis".equals(input)) {
|
||||
|
|
|
@ -19,10 +19,21 @@
|
|||
|
||||
package org.elasticsearch.util.json;
|
||||
|
||||
import org.codehaus.jackson.JsonFactory;
|
||||
import org.codehaus.jackson.JsonGenerator;
|
||||
import org.codehaus.jackson.JsonParser;
|
||||
import org.codehaus.jackson.*;
|
||||
import org.codehaus.jackson.map.DeserializationContext;
|
||||
import org.codehaus.jackson.map.ObjectMapper;
|
||||
import org.codehaus.jackson.map.SerializerProvider;
|
||||
import org.codehaus.jackson.map.deser.CustomDeserializerFactory;
|
||||
import org.codehaus.jackson.map.deser.StdDeserializer;
|
||||
import org.codehaus.jackson.map.deser.StdDeserializerProvider;
|
||||
import org.codehaus.jackson.map.ser.CustomSerializerFactory;
|
||||
import org.codehaus.jackson.map.ser.SerializerBase;
|
||||
import org.elasticsearch.util.joda.FormatDateTimeFormatter;
|
||||
import org.elasticsearch.util.joda.Joda;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* A set of helper methods for Jackson.
|
||||
|
@ -33,14 +44,21 @@ public final class Jackson {
|
|||
|
||||
private static final JsonFactory defaultJsonFactory;
|
||||
|
||||
private static final ObjectMapper defaultObjectMapper;
|
||||
|
||||
static {
|
||||
defaultJsonFactory = newJsonFactory();
|
||||
defaultObjectMapper = newObjectMapper();
|
||||
}
|
||||
|
||||
public static JsonFactory defaultJsonFactory() {
|
||||
return defaultJsonFactory;
|
||||
}
|
||||
|
||||
public static ObjectMapper defaultObjectMapper() {
|
||||
return defaultObjectMapper;
|
||||
}
|
||||
|
||||
public static JsonFactory newJsonFactory() {
|
||||
JsonFactory jsonFactory = new JsonFactory();
|
||||
jsonFactory.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
|
||||
|
@ -52,10 +70,82 @@ public final class Jackson {
|
|||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
|
||||
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, true);
|
||||
|
||||
CustomSerializerFactory serializerFactory = new CustomSerializerFactory();
|
||||
serializerFactory.addSpecificMapping(Date.class, new DateSerializer());
|
||||
serializerFactory.addSpecificMapping(DateTime.class, new DateTimeSerializer());
|
||||
mapper.setSerializerFactory(serializerFactory);
|
||||
|
||||
CustomDeserializerFactory deserializerFactory = new CustomDeserializerFactory();
|
||||
deserializerFactory.addSpecificMapping(Date.class, new DateDeserializer());
|
||||
deserializerFactory.addSpecificMapping(DateTime.class, new DateTimeDeserializer());
|
||||
mapper.setDeserializerProvider(new StdDeserializerProvider(deserializerFactory));
|
||||
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private Jackson() {
|
||||
|
||||
}
|
||||
|
||||
public static class DateDeserializer extends StdDeserializer<Date> {
|
||||
|
||||
private final FormatDateTimeFormatter formatter = Joda.forPattern("dateTime");
|
||||
|
||||
public DateDeserializer() {
|
||||
super(Date.class);
|
||||
}
|
||||
|
||||
@Override public Date deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
JsonToken t = jp.getCurrentToken();
|
||||
if (t == JsonToken.VALUE_STRING) {
|
||||
return new Date(formatter.parser().parseMillis(jp.getText()));
|
||||
}
|
||||
throw ctxt.mappingException(getValueClass());
|
||||
}
|
||||
}
|
||||
|
||||
public final static class DateSerializer extends SerializerBase<Date> {
|
||||
|
||||
private final FormatDateTimeFormatter formatter = Joda.forPattern("dateTime");
|
||||
|
||||
@Override public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
|
||||
jgen.writeString(formatter.parser().print(value.getTime()));
|
||||
}
|
||||
|
||||
@Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
|
||||
return createSchemaNode("string", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DateTimeDeserializer extends StdDeserializer<DateTime> {
|
||||
|
||||
private final FormatDateTimeFormatter formatter = Joda.forPattern("dateTime");
|
||||
|
||||
public DateTimeDeserializer() {
|
||||
super(DateTime.class);
|
||||
}
|
||||
|
||||
@Override public DateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
|
||||
JsonToken t = jp.getCurrentToken();
|
||||
if (t == JsonToken.VALUE_STRING) {
|
||||
return formatter.parser().parseDateTime(jp.getText());
|
||||
}
|
||||
throw ctxt.mappingException(getValueClass());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public final static class DateTimeSerializer extends SerializerBase<DateTime> {
|
||||
|
||||
private final FormatDateTimeFormatter formatter = Joda.forPattern("dateTime");
|
||||
|
||||
@Override public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
|
||||
jgen.writeString(formatter.printer().print(value));
|
||||
}
|
||||
|
||||
@Override public JsonNode getSchema(SerializerProvider provider, java.lang.reflect.Type typeHint) {
|
||||
return createSchemaNode("string", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,17 +22,24 @@ package org.elasticsearch.util.json;
|
|||
import org.codehaus.jackson.JsonEncoding;
|
||||
import org.codehaus.jackson.JsonGenerator;
|
||||
import org.codehaus.jackson.JsonNode;
|
||||
import org.elasticsearch.util.MapBuilder;
|
||||
import org.elasticsearch.util.io.FastByteArrayInputStream;
|
||||
import org.elasticsearch.util.io.FastByteArrayOutputStream;
|
||||
import org.elasticsearch.util.io.FastCharArrayWriter;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.util.json.Jackson.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
@Test
|
||||
public class JsonBuilderTests {
|
||||
|
||||
@Test public void verifyReuseJsonGenerator() throws Exception {
|
||||
|
@ -83,4 +90,14 @@ public class JsonBuilderTests {
|
|||
JsonNode node = Jackson.newObjectMapper().readValue(new FastByteArrayInputStream(data), JsonNode.class);
|
||||
assertThat(node.get("source").get("test").getTextValue(), equalTo("value"));
|
||||
}
|
||||
|
||||
@Test public void testDatesObjectMapper() throws Exception {
|
||||
Date date = new Date();
|
||||
DateTime dateTime = new DateTime();
|
||||
Map<String, Object> data = MapBuilder.<String, Object>newMapBuilder()
|
||||
.put("date", date)
|
||||
.put("dateTime", dateTime)
|
||||
.map();
|
||||
System.out.println("Data: " + defaultObjectMapper().writeValueAsString(data));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue