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 ObjectMapper
s 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
Converting Many 'If Else' Statements to a Cleaner Approach
Using Java to Find Substring of a Bigger String Using Regular Expression
Why Won't This Generic Java Code Compile
Multi-Project Test Dependencies with Gradle
How to Format Decimals in a Currency Format
How to Turn a String into a Inputstreamreader in Java
Surefire Is Not Picking Up Junit 5 Tests
Expression Language in Jsp Not Working
Get Edited Treenode from a Celleditorlistener
@Runwith(Mockitojunitrunner.Class) VS Mockitoannotations.Initmocks(This)
Ideal Method to Truncate a String with Ellipsis
How to Represent Double Values as Circles in a 2D Matrix in Java
Can a Java File Have More Than One Class
How Can Non-Ascii Characters Be Removed from a String
How to Calculate the Number of Rows (And Columns in Each Row) a Text Takes in a Jtextarea
Unsupportedtemporaltypeexception When Formatting Instant to String