3

I am using jackson library and I have came across a situation where I want to disable @JsonFormat annotation using objectmapper while serialization/deserialization.

My Api code is in 3rd party library so i can't remove/add any annotation, so objectMapper is the only choice.

Api class:

public class ApiClass {

  @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
  private DateTime time;

}

My code:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.configure(Feature.ALLOW_COMMENTS, true);
objectMapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.setSerializationInclusion(Include.NON_ABSENT);
objectMapper.registerModule(new JodaModule());
objectMapper.registerModule(new JavaTimeModule());

String str = " {\"time\": \"2012-05-01\"}";

ApiClass msg = objectMapper.readValue(str, ApiClass.class);

I want this conversion to happen successfully.

Currently I am getting: com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2012-05-01" is too short

Please help me here.

Thanks in advance

Charu Jain
  • 852
  • 1
  • 7
  • 18

5 Answers5

7

Below is the code that will disable JsonFormat specifically:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.configure(Feature.ALLOW_COMMENTS, true);
objectMapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, true);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
objectMapper.setSerializationInclusion(Include.NON_ABSENT);
objectMapper.registerModule(new JodaModule());
objectMapper.registerModule(new JavaTimeModule());

objectMapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
    @Override
    protected <A extends Annotation> A _findAnnotation(final Annotated annotated,
        final Class<A> annoClass) {
      if (!annotated.hasAnnotation(JsonFormat.class)) {    //since we need to disable JsonFormat annotation.
        return super._findAnnotation(annotated, annoClass);
      }
      return null;
    }
  });


String str = " {\"time\": \"2012-05-01\"}";

ApiClass msg = objectMapper.readValue(str, ApiClass.class);
System.out.println(objectMapper.writeValueAsString(msg ));

In case we need to disable multiple annotations(JsonFormat, JsonUnWrapped) then:

replace:

if (!annotated.hasAnnotation(JsonFormat.class)) {

with:

if (!annotated.hasOneOf(new Class[] {JsonFormat.class, JsonUnwrapped.class})) {

Thanks all.

Charu Jain
  • 852
  • 1
  • 7
  • 18
0

Try below code before using readValue method

mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"));
AbhiN
  • 642
  • 4
  • 18
  • Doesn't work, got: com.fasterxml.jackson.databind.JsonMappingException: Invalid format: "2012-05-01" is too short – Charu Jain Sep 30 '19 at 09:38
0

Try using custom deserializer:

public class MyTest {
    @Test
    public void myTest() throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        objectMapper.configure(MapperFeature.AUTO_DETECT_IS_GETTERS, true);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
        objectMapper.registerModule(new JavaTimeModule());

        String str = " {\"time\": \"2012-05-01\"}";


        SimpleModule module = new SimpleModule();
        module.addDeserializer(DateTime.class, new DateTimeDeserializer());
        objectMapper.registerModule(module);


        ApiClass msg = objectMapper.readValue(str, ApiClass.class);
        System.out.println(msg.getTime());
    }
}

class ApiClass {

    @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'")
    private DateTime time;

    public DateTime getTime() {
        return time;
    }

    public void setTime(DateTime time) {
        this.time = time;
    }
}

class DateTimeDeserializer extends StdDeserializer<DateTime> {

    public DateTimeDeserializer() {
        this(null);
    }

    public DateTimeDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public DateTime deserialize(JsonParser jp, DeserializationContext ctxt)
        throws IOException {
        JsonNode node = jp.getCodec().readTree(jp);
        String time = node.asText();
        return new DateTime(time);
    }
}
Vivek Gupta
  • 2,534
  • 3
  • 15
  • 28
  • Caused by: java.lang.IllegalArgumentException: Invalid format: "2012-05-01" is too short – Charu Jain Sep 30 '19 at 10:31
  • I have tested this myself on my local, this works, which jackson and java version you are using – Vivek Gupta Sep 30 '19 at 10:59
  • pattern you have taken is incorrect, @JsonFormat(pattern = "yyyy-MM-dd"), Please check the pattern in my question. – Charu Jain Sep 30 '19 at 12:15
  • answer updated, was a silly mistake from in copying from IDE to here – Vivek Gupta Sep 30 '19 at 12:38
  • you can even do away with : `objectMapper.registerModule(new JodaModule())` as you anyways have to write custom deserializer – Vivek Gupta Sep 30 '19 at 12:41
  • If I do System.out.println(objectMapper.writeValueAsString(msg)); Then I get all time details: {"time":{"era":1,"dayOfMonth":1,"dayOfWeek":2,"dayOfYear":122,"weekyear":2012,"monthOfYear":5,"hourOfDay":0,"minuteOfHour":0,"millisOfDay":0,"yearOfEra":.....} – Charu Jain Oct 01 '19 at 11:47
  • If I need to preserve the msg format and only need to change time, do you have an idea what needs to be done? – Charu Jain Oct 01 '19 at 11:49
0

There is one solution for the problem.

Please check: https://www.baeldung.com/jackson-annotations Point no. 9 Disable Jackson Annotation

objectMapper.disable(MapperFeature.USE_ANNOTATIONS);
ApiClass msg = objectMapper.readValue(str, ApiClass.class);

sout(msg.getTime()) //2012-05-01T00:00:00.000Z

But this will disable all annotations. I just want to disable @JsonFormat annotation. Please suggest.

Charu Jain
  • 852
  • 1
  • 7
  • 18
  • this is another way to do this, could be good in your particular use case. But the huge issue which could arise with this, if there are multiple annotations and you want to do away with just one of them. – Vivek Gupta Oct 01 '19 at 05:11
  • @VivekGupta: this is another issue now. do you know how to disable only specific annotation? – Charu Jain Oct 01 '19 at 11:50
  • i am not sure about that.. i believe if you are facing this issue, then you better write a custom deserializer for joda datetime and add that as a simple module as given in my answer below instead of disabling annotations, the one i have shared is tried and tested – Vivek Gupta Oct 01 '19 at 12:43
  • Yes, please check my above answer. – Charu Jain Oct 04 '19 at 08:53
-1

You can use SimpleDateFormat to convert string type date into date type like below

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    try {
        Date parse = simpleDateFormat.parse(String date);
        return parse;
    } catch (ParseException e) {
        e.printStackTrace();
    }