protected DateTime parseLocal(JsonParser jp) throws IOException, JsonProcessingException {
   String str = jp.getText().trim();
   if (str.length() == 0) { // [JACKSON-360]
     return null;
   }
   return _localDateTimeFormat.parseDateTime(str);
 }
 protected String _valueDesc() {
   try {
     return _desc(_parser.getText());
   } catch (Exception e) {
     return "[N/A]";
   }
 }
 @Override
 public ReadablePeriod deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   // TODO: perhaps support array of numbers...
   // if (jp.isExpectedStartArrayToken()) { ]
   switch (jp.getCurrentToken()) {
     case VALUE_NUMBER_INT: // assume it's millisecond count
       return new Period(jp.getLongValue());
     case VALUE_STRING:
       return new Period(jp.getText());
   }
   throw ctxt.wrongTokenException(jp, JsonToken.START_ARRAY, "expected JSON Number or String");
 }
 @SuppressWarnings("unchecked")
 @Override
 public T deserialize(JsonParser jp, DeserializationContext ctxt)
     throws IOException, JsonProcessingException {
   JsonToken t = jp.getCurrentToken();
   if (t == JsonToken.VALUE_NUMBER_INT) {
     return (T) new DateTime(jp.getLongValue(), DateTimeZone.UTC);
   }
   if (t == JsonToken.VALUE_STRING) {
     String str = jp.getText().trim();
     if (str.length() == 0) { // [JACKSON-360]
       return null;
     }
     return (T) new DateTime(str, DateTimeZone.UTC);
   }
   throw ctxt.mappingException(getValueClass());
 }
 @Override
 public CustomMap deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
   CustomMap result = new CustomMap();
   result.put("x", jp.getText());
   return result;
 }