Maven build:
mvn clean package
Create database and user with sql/mysql_create_db_user.sql:
mysql -u root < sql/mysql_create_db_user.sql
Maven build:
mvn -P mysql clean package
java -jar target/homework-szfilep-1.0-SNAPSHOT.jar
java -jar target/homework-szfilep-1.0-SNAPSHOT.jar --spring.profiles.active=mysql
Best way to test it with a rest client. E.g. Google Chrome Postman plugin.
By default 3 molecule is stored in db so open this in a browser just give you a representation:
http://localhost:8080/molecule?externalId=1
For POST don't forget to add the following http header:
Content-Type: application/json;charset=UTF-8
and post it to:
http://localhost:8080/molecule
http body:
{
"externalId": "4",
"textRepresentation": "{atoms:[C,O,C,C]}",
"metadata": [
{
"metadataKey": "metadata1",
"metadataValue": "value1"
},
{
"metadataKey": "m1",
"metadataValue": "v1"
}
]
}
As a Java developer I prefer Java frameworks. Possible solutions could be:
- basic servlet-api: too much work to parse http parameters and body
- Java EE with jax-rs: good concept, some configuration is needed, could do the job
- Spring REST: similar concept than JAX-RS, but a bit easier application development with Spring Boot. It is also poosible to have different representation of the molecule resource. I used only JSON. I chose this one.
- Spring HATEOAS: using standard HAL syntax and hateoas library implementation would be really easy and RESTfullness would work just by default. I didn't choose, because it is too specific and it only support the HAL representation of the resources.
Molecule entity is quite straight forward, but storing metadata raises some question about its primary key. My first thought was to create a composite key containing the molecule's externalId and the metadata key. But to represent this in a JPA entity the compsite key should be extracted to a separate IdClass or Embeddable class. It works, but it has two drawbacks:
- The embeddable class appears in the JSON representation, or the properties have to be duplicated.
- It doesn't support to have multiple metadata for a molecule with the same key, which seems obvious, but it is not in the specification.
So I decieded to add a technical autogenerated id to the MetadataEntry entity and hide it from the JSON representation. Later, if we want to modify an existing molecule through REST, we have to handle this id carefully, but currently modification is not possible.
As metadata belongs to a molecule, I didn't create separate repository for it. I only set cascading type to ALL to the @OneToMany relationship and also set to EAGER fetch, so we can be sure it is on hand when we dealing with molecule's data.
Creating a REST API it is required to use the standard HTTP error codes sending back to the client. I created global exception handlers, so in case of any validation error the client receives a 4xx error code along with a standard json body where the error is explained.
I investigated whether I have to override equals() and hashCode() methods in the entities and I decided not to. It is not necessary on any level of the code. Although for the unit tests it can be useful.
I wrote unit tests for the controller and service classes with mockito and junit and integration tests for testing the REST API.