Skip to content

adjusting the csv reader#3

Open
mohammedsaad wants to merge 33 commits into
masterfrom
XmlReader
Open

adjusting the csv reader#3
mohammedsaad wants to merge 33 commits into
masterfrom
XmlReader

Conversation

@mohammedsaad

Copy link
Copy Markdown
Collaborator

i have done some implementation to the csv reader

i added tika to dependancy to use it for getting the mimeType
i update the getFile to toURI
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 matthesrieke left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +16 to +19
@Bean
public Logger getLogger(){
return LoggerFactory.getLogger(DatareaderApplication.class);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for this guidance; I have implemented it.

Comment on lines +46 to +52
CsvParser csvParser = new CsvParser();
try {
csvParser.readCsvFile(o);
} catch (ParseException e) {
e.printStackTrace();
}
measurements = csvParser.getContent();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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"))

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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> {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of an external library for CSV parsing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants