Extending the Patient Model
Our basic Patient domain object is not very exciting and lacks the typical data elements that one might expect. If we do a little research on sites like schema.org, we can see that there are definitions already out there for a Patient.
Let’s use some of that information to start filling out the domain.
Make the Patient model a bit more… interesting
Add the following attributes to the Patient entity (and Add the associated getter/setters using your IDEs code generator if possible):
private String givenName;
private String familyName;
private LocalDate birthDate;
Using curl again submit a Patient add request:
curl -sS -H "Content-Type: application/json" -X POST localhost:8080/patients -d '{"givenName":"Max","familyName":"Colorado","birthDate":"1942-12-11"}' | jq
400 Error?
So the LocalDate type is causes a JsonMappingException. We need to add a Jackson module dependency to the project so it knows how to handle JSR 310 Dates (introduced in Java 8).
Add this dependency to the project pom.xml
:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
Refresh the dependencies and restart the application (Spring Boot will automatically register this module with the default Jackson ObjectMapper).
Now if we execute the curl
again, we see an odd looking date structure:
"birthDate": [
1942,
12,
11
]
While an accurate date, that isn’t exactly the JSON structure what we want. There is yet another configuration change we need here to tell Jackson to format the date correctly.
Update the application.properties
in resources and include the property:
spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
This somewhat confusingly named configuration option tells Jackson to output Dates in ISO-8601 textual value. This is probably the configuration that you’ll want to use in most applications.
But wait.
If we look at how the date was actually stored in the database through the H2 console, it looks like a BLOB. That isn’t a good choice since we might want to be able to query against it later.
// TODO: Discuss why JPA doesn’t support LocalDate?
Fixing the LocalDate Time Database Mapping
Okay, I lied. I said not to worry about the actual database implementation at this point, but we are going to take this one detour.
In general, you shouldn’t normally need worry too much about the type mappings until much later in the design process but this specific issue can be resolved fairly easy during the initial project set up.
As of the time of writing, JPA does not natively support the JSR 310 dates. Fortunately, Hibernate stepped in and provides an additional library to help with managing the type conversions. You can read more about it here.
Thankfully, it is just as simple as adding the following dependency to your
pom.xml
:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-java8</artifactId>
<version>${hibernate.version}</version>
</dependency>
This library will introduce the appropriate type converters that will deal with the new date types in a more elegant fashion. When you refresh the dependencies and restart the application, you will see in the logs that the table is now being create with a proper DATE type:
Hibernate:
create table patient (
id bigint generated by default as identity,
birth_date date,
family_name varchar(255),
given_name varchar(255),
primary key (id)
)
The need for this additional library will eventually go away when Spring Boot upgrades to Hibernate 5.2 (see the Hibernate Migration Guide 5.2).