Reputation: 155
I am trying to read the data from two different files one is in csv format and another file is from xml data.using completeFuture I am trying to read the data from two files async. I am getting the type conversion error. Please let me know whether I am following the proper approach to use the completefuture object here in the below code
Exception:
java.lang.ClassCastException: class java.util.ArrayList cannot be cast to class java.util.function.Supplier (java.util.ArrayList and java.util.function.Supplier are in module java.base of loader 'bootstrap')
code to read the data from main thread
CompletableFuture<Object> csvdata = CompletableFuture.supplyAsync((Supplier<Object>) processdatacsv());
CompletableFuture<Object> xmldata1 = CompletableFuture.supplyAsync((Supplier<Object>) processxmldata());
List<String[]> csvfiledata = null;
if (csvdata.isDone())
csvfiledata = (List<String[]>) csvdata.get();
List<String[]> xmlfiledata = null;
if (xmldata1.isDone())
xmlfiledata = (List<String[]>) xmldata1.get();
private List<String[]> processdatacsv() {
CSVReader reader = null;
Resource resource1 = new ClassPathResource("sample.csv");
try {
String csvFile = resource1.getFile().toString();
reader = new CSVReader(new FileReader(csvFile));
return reader.readAll();
} catch (Exception e) {
LOGGER.error("Error while process csv records");
return null;
}
}
private List<String[]> processxmldata() {
Resource resource = new ClassPathResource("sample.xml");
File file;
try {
file = resource.getFile();
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(file);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("record");
System.out.println("Root element :" + doc.getDocumentElement().getNodeName());
List<String[]> dataList = new ArrayList<String[]>();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) node;
String[] data = new String[3];
data[0] = eElement.getAttribute("reference").toString();
data[1] = eElement.getElementsByTagName("Number").item(0).getTextContent().toString();
data[2] = eElement.getElementsByTagName("des").item(0).getTextContent().toString();
}
}
return dataList;
} catch (Exception e) {
LOGGER.error("Error while process csv records");
return null;
}
}
Upvotes: 0
Views: 1925
Reputation: 4833
For CompletableFuture.supplyAsync
you need a Supplier
. This cannot be done by casting a list to the type Supplier<Object>
. The correct way would be this:
CompletableFuture<List<String[]>> xmldata1 = CompletableFuture.supplyAsync(() -> processxmldata());
The reason for using a Supplier
is that evaluation must not start immediately with the statement constructing the Supplier
. The Future
will start evaluation in the asynchronous thread.
Later on, if you really need the result, you must wait for it. The simplest way to do this is just:
xmlfiledata = xmldata1.get();
Have a look at the javadoc of the get method.
Upvotes: 1
Reputation: 2575
Like the exception says: you can't just cast a list to a supplier object. A Supplier is an object that has a get-method to request the object that it supplies (a list in your case).
In your code the files wouldn't be loaded asynchronusly, because you are calling the methods processdatacsv
and processxmldata
directly, so they would be executed directly. To execute the methods later (and in another thread) you need the Supplier (so the other thread can call the get-method and execute the code).
In the code you provided in your question it would be the easiest to use lambda expressions like this:
CompletableFuture<List<String[]>> csvdata = CompletableFuture.supplyAsync(() -> processdatacsv());
CompletableFuture<List<String[]>> xmldata1 = CompletableFuture.supplyAsync(() -> processxmldata());
In this code snippet the part () -> processdatacsv()
could be interpreted like: create a new Supplier object which calls the method processdatacsv
from it's method get
.
Or you can do it like this (maybe easier to understand):
CompletableFuture<List<String[]>> csvdata = CompletableFuture.supplyAsync(new Supplier<List<String[]>>() {
public List<String[]> get() {
processdatacsv();
}
});
CompletableFuture<List<String[]>> csvdata = CompletableFuture.supplyAsync(new Supplier<List<String[]>>() {
public List<String[]> get() {
processxmldata();
}
});
Upvotes: 1