Date Format Mapping to JSON Jackson

Date format Mapping to JSON Jackson

What is the formatting I need to use to carry out conversion with Jackson? Is Date a good field type for this?

Date is a fine field type for this. You can make the JSON parse-able pretty easily by using ObjectMapper.setDateFormat:

DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm a z");
myObjectMapper.setDateFormat(df);

In general, is there a way to process the variables before they get mapped to Object members by Jackson? Something like, changing the format, calculations, etc.

Yes. You have a few options, including implementing a custom JsonDeserializer, e.g. extending JsonDeserializer<Date>. This is a good start.

Date format Mapping to JSON Jackson Not working properly

Disable serializing dates as timestamps on Jackson's ObjectMapper. E.g.

mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

Annotate the date field appropriately. E.g.

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="dd-M-yyyy hh:mm:ss")
private Date date;

or also set the format on the ObjectMapper

DateFormat df = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
mapper.setDateFormat(df);

Docs for JsonFormat

jackson json date format convert

You can use custom deserializer.

public class EmployeeBirthDateDeserializer extends StdDeserializer<LocalDate> {

public EmployeeBirthDateDeserializer() {
super(LocalDate.class);
}

@Override
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode root = parser.getCodec().readTree(parser);
return LocalDate.of(root.get("year").asInt(), root.get("monthValue").asInt(), root.get("dayOfMonth").asInt());
}
}

Then apply it only to dateOfBirth field in Employee using @JsonDeserialize:

public class Employee {

@JsonDeserialize(using = EmployeeBirthDateDeserializer.class)
private LocalDate dateOfBirth;

//getters and setter
}

Test:

public class Temp {

public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Employee employee = mapper.readValue(ClassLoader.getSystemResourceAsStream("strange-date.json"), Employee.class);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
System.out.println(formatter.format(employee.getDateOfBirth()));
}
}

Prints: 1980-05-04.

Jackson ObjectMapper not respecting configured date time format

You missed a minor thing.
You should resolve the type to Map<String, Date> instead of Map<String, Object> as follow:

        Map<String, Date> jsonDataMap = mapper.readValue(jsonString, new TypeReference<Map<String, Date>>() {});

Jackson @JsonFormat converting date with incorrect timezone

Simple solution: I solved it by changing the data type to String which completes my aim to capture the value as it is coming from JSON payload. Using Date and other data types were converting the value to some different timezone.

@JsonProperty("callStartTime")
@Column(name = "call_start_dt", nullable = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", lenient = OptBoolean.FALSE)
private **String** callStartTime;

Jackson JSON date format serialization based on condition

"...how can I control the date format based on conditions from for instance the URL (more exactly from the outside) for each message"

Though a little bit more work, one way is to create different ObjectMappers configured differently for each type of request. To determine which one will be used we can make the decision inside a ContextResolver. We could inject a UriInfo into the resolver, to get the value of the @PathParam("country"). Then make the decision from that, which mapper will be used. For example

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

private final ObjectMapper sweMapper;
private final ObjectMapper norMapper;
private final ObjectMapper defaultMapper;

@Context
private UriInfo uriInfo;

public ObjectMapperContextResolver() {
defaultMapper = new ObjectMapper();

sweMapper = new ObjectMapper();
SimpleModule sweModule = new SimpleModule("SweModule", new Version(1,0,0,null));
sweModule.addDeserializer(Date.class, new JsonDateDeserializer(sweFormat));
sweModule.addSerializer(Date.class, new JsonDateSerializer(sweFormat));
sweMapper.registerModule(sweModule);

norMapper = new ObjectMapper();
SimpleModule norModule = new SimpleModule("NorModule", new Version(1,0,0,null));
norModule.addDeserializer(Date.class, new JsonDateDeserializer(norFormat));
norModule.addSerializer(Date.class, new JsonDateSerializer(norFormat));
norMapper.registerModule(norModule);
}

@Override
public ObjectMapper getContext(Class<?> type) {
String country = uriInfo.getPathParameters().getFirst("country");
if (country == null) {
return defaultMapper;
}

switch (country) {
case "se": return sweMapper;
case "no": return norMapper;
default: return defaultMapper;
}
}
}

The reason we are using three mapper is for one, they are expensive to create. Secondly, configuring them is not thread-safe. And since the ContextResolver will be a singleton, only one of the mappers will be used for the application. So we just create three for different cases.

If you go this route, you should also remember to remove the serialization annotations from the field.



UPDATE

So with Jersey 2.6, it seems there is a problem with the above solution. It just fails on startup. The solution I was able to find was to not use this dependency

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey-version}</version>
</dependency>

Seem loading of some part of this module causes it to fail. Instead just use the Pure Jackson dependency (which the above actually pulls in and uses itself).

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.9.13</version>
</dependency>

Note: jersey-json:1.6 uses 1.7.1 of the above dependency. I just switched to use the latest 1.x version. So you may or may not want to switch it back.

Get rid of any you might have for the old artifact, i.e

<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>

And add the Jackson package as a package to scan

<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>
com.your.packages,
org.codehaus.jackson.jaxrs
</param-value>
</init-param>

Or if you are using some Mule specific configuration, just register these

  • org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider
  • org.codehaus.jackson.jaxrs.JacksonMappingExceptionMapper
  • org.codehaus.jackson.jaxrs.JacksonParseExceptionMapper


Related Topics



Leave a reply



Submit