adjusting the csv reader#3
Conversation
i added tika to dependancy to use it for getting the mimeType
i update the getFile to toURI
update the code for readbiltiy
to ensure consisteny we used Tika as JDK 8 has a bug using Files.probeContentType
this class used to format date
this is a library to read csv
create a class that contatins a collection of the measuremants
i update date formatter to extend xml adapter that used in marshalling and unmarshal. these overided methtods are requried in JAXB
added toString method
added the annotations required for JAXB
added annotations required by JAXB with refactoring for the names of the methods
add the dependancies required by JAXB
refactor to the CSVReader
adding dateFormatter Object
update the custom date format to be public which is used in the JsonParser.java
adding Jason Property to the class variables to be recognized by Jakson Object mapper
refactoring the naming of the properties to be constant for ensuring consistency in case of changing the attributes' names
reduce redundancy of filed names and get it from the class definition
change the JABX version to solve this warning ⬇️ WARNING: Illegal reflective access by com.sun.xml.bind.v2.runtime.reflect.opt.Injector
updated the XML parser and JSON parser to throw io exception in case the given was neither path nor inputStream
add spring-boot-starter-web dependency to the pom move the class Measurement and class Measurements deom model package to Business.domain move the parser classes to business.service
update JsonReader and XmlReader so the mimeType is being refered from MediaType.APPLICATION_JSON_VALUE
matthesrieke
left a comment
There was a problem hiding this comment.
hi @mohammedsaad I finally was able to do the code review. We can have a chat about it tomorrow, and also plan on the next steps/tasks
| @Bean | ||
| public Logger getLogger(){ | ||
| return LoggerFactory.getLogger(DatareaderApplication.class); | ||
| } |
There was a problem hiding this comment.
Good thought on using Dependency Injection for the Logger. Still, DI would not perfectly work here - at least not with a singleton Bean.
The log messages would be all coming from the same logger instance and result in something like this:
10:34:47.168 [main] INFO org.n52.datareader.DatareaderApplication: message abcdef
10:34:47.168 [main] INFO org.n52.datareader.DatareaderApplication: another message from another class
The idea of the log is to allow the people inspecting the log to identify where and when something happend (e.g. an error occurred). With the singleton bean, everything appears to happen in the DatareadApplication.class.
When using like private static final Logger LOG = LoggerFactory.getLogger(<the-class>);, the log would look like:
10:34:47.168 [main] INFO org.n52.datareader.DatareaderApplication: message abcdef
10:34:47.168 [main] INFO org.n52.datareader.web.service.XmlController: another message from another class
There are some other solutions, e.g. with some post-processing in the Beans (https://stackoverflow.com/a/6353250). These are all a little more complex, or even more "magical" then Spring already is (e.g. via Lombok).
There was a problem hiding this comment.
thanks for this guidance; I have implemented it.
| CsvParser csvParser = new CsvParser(); | ||
| try { | ||
| csvParser.readCsvFile(o); | ||
| } catch (ParseException e) { | ||
| e.printStackTrace(); | ||
| } | ||
| measurements = csvParser.getContent(); |
There was a problem hiding this comment.
Your CsvParser (and the other *Parser classes as well) could also be designed stateless. At the moment they have one method to parse the contents of the file. As this method is storing the result in a class field, one object of CsvParser cannot be shared by different threads (e.g. when many requests are coming into the web application). You could just return the Measurements object from the readCsvFile() method. The method would then only have method-scoped variables which makes it thread-safe.
| Spliterator<Path> F = directoryStream.spliterator(); | ||
| StreamSupport.stream(F, true).forEach(dataFile -> { | ||
| try { | ||
| Tika tika = new Tika(); |
There was a problem hiding this comment.
Good use of an external library! Its always good to re-use well-tested code, and with a framework such as Tika you are good to go!
| mimeType = MediaType.APPLICATION_JSON_VALUE; | ||
| else if (dataType.equals("csv-data")) | ||
| mimeType = "text/csv"; | ||
| else return null; |
There was a problem hiding this comment.
return null is in most cases not a good idea. Here, the user would get back an empty response (I guess, did not test it). It would be better to inform the user about the "exceptional" situation (which is: the application could not handle the request). E.g.:
throw new IOException("Data type not supported: " + dataType);
| public List<Measurement> readXmlData(@PathVariable("data") String dataType) throws Exception { | ||
| List<Measurement> measurements = null; | ||
| String mimeType; | ||
| if (dataType.equals("xml-data")) |
There was a problem hiding this comment.
In general, this solution of course works. Still, imho it is a better approach to use multiple methods for each URL. This is more transparent (although a bit more lines of code are created) and flexible (you could have different Content-Type ("produces") for each method:
@RequestMapping(method = RequestMethod.GET, value = "/xml-data", produces = "application/json")
public List<Measurement> readXmlData() throws Exception { ...
@RequestMapping(method = RequestMethod.GET, value = "/json-data", produces = "application/json")
public List<Measurement> readJsonData() throws Exception { ...
Nevertheless, now you know about @PathVariable :-)
| } | ||
| * | ||
| * */ | ||
| public class DateFormatter extends XmlAdapter<String, Date> { |
There was a problem hiding this comment.
Good job on adding custom parsing within JAXB!
| public void readCsvFile(Object source) throws IOException, ParseException { | ||
| Iterable<CSVRecord> records; | ||
| DateFormatter dateFormatter = new DateFormatter(); | ||
| CSVFormat csvFormat = CSVFormat.EXCEL.withDelimiter(';').withHeader().withSkipHeaderRecord(); |
There was a problem hiding this comment.
Good use of an external library for CSV parsing.
i have done some implementation to the csv reader