Background: My application is built on top of Spring Data REST and MongoDB Repositories.
Consider this simple Java domain object with a YearMonth
field:
@Getter @Setter
public class Console {
@Id private String id;
private String name;
private YearMonth releaseMonth;
private Vendor vendor;
}
And this domain object is made available for persistence by a MongoRepository implementation:
public interface ConsoleRepository extends MongoRepository<Console, String> {
Console findByName(@Param("name") String name);
}
When exposing a REST Controller (automatically by Data REST) to manage this domain object, I've added jackson-datatype-jsr310
gradle dependency in order to parse YearMonth JSON values (e.g.: "2016-04") into this field by jackson:
compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.6.1'
When POST'ing to this endpoint, the YearMonth value contained on the JSON document is correctly parsed into a YearMonth field and the whole object is stored as a document on MongoDB successfully. Looking up this document on mongo proves that:
> db.console.find()
{ "_id" : ObjectId("575f837ca75df1fc7e5f4f96"),
"_class" : "xxx.yyy.Console",
"name" : "Console 1",
"releaseMonth" : { "year" : 1988, "month" : 10 },
"vendor" : "VENDOR_1" }
However, when I try to GET that resource from the REST controller, MongoDB client fails to bind this YearMonth value into the Java object:
GET localhost:8080/consoles
Response:
{
"timestamp": 1465954648903,
"status": 500,
"error": "Internal Server Error",
"exception": "org.springframework.data.mapping.model.MappingException",
"message": "No property null found on entity class java.time.YearMonth to bind constructor parameter to!",
"path": "/consoles"
}
I'd assume MongoDB Java client lacks built-in support for Java 8's YearMonth values, but since it is being able to save them, that seems to be ruled out. What am I missing here?
I was able to parse this object by creating a Custom Converter:
@Component
public class DBObjectToYearMonthConverter implements Converter<DBObject, YearMonth> {
@Override
public YearMonth convert(DBObject source) {
return YearMonth.of(
(int) source.get("year"),
(int) source.get("month")
);
}
}
And setting up a CustomConversions @Bean on Application class:
@Bean
public CustomConversions getCustomConversions() {
return new CustomConversions(Arrays.asList(
new DBObjectToYearMonthConverter()
));
}
Other options are welcome.