linkedin/parseq

Task.par() doesn't work with Vavr List, throw ClassCastException

WeishiZeng opened this issue · 4 comments

Class: com.linkedin.parseq.Task
Method:

public static <T> ParTask<T> par(final Iterable<? extends Task<? extends T>> tasks) {

Use case to reproduce:

    List<Task<MyObject>> javaList = new ArrayList<>();
    javaList.add(t1);
    javaList.add(t2);

    io.vavr.collection.List<Task<MyObject>> vavrList = io.vavr.collection.List.of(t1,t2);

    Task.par(vavrList);  //this line will fail at Runtime: "java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.linkedin.parseq.Task;"
    Task.par(javaList);  //this works fine

StackTrace:

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.linkedin.parseq.Task;

	at com.linkedin.parseq.ParTaskImpl.tasksFromIterable(ParTaskImpl.java:76)
	at com.linkedin.parseq.ParTaskImpl.<init>(ParTaskImpl.java:60)
	at com.linkedin.parseq.Task.par(Task.java:1750)
	at [method calling Task.par]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:583)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
	at org.testng.TestRunner.privateRun(TestRunner.java:648)
	at org.testng.TestRunner.run(TestRunner.java:505)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
	at org.testng.SuiteRunner.run(SuiteRunner.java:364)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
	at org.testng.TestNG.runSuites(TestNG.java:1049)
	at org.testng.TestNG.run(TestNG.java:1017)
	at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:73)
	at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)

The reason this happens is that arrays in java are not covariant.

This is probably an issue with any Iterable that does not extend Collection

return (Task<? extends Task<? extends T>>[]) taskList.toArray();

Here an unsafe cast is performed that will always fail since you can't cast an Object[] to a Task[]
Fix should be create a new Task[] the same size of the ArrayList then call https://docs.oracle.com/javase/8/docs/api/java/util/List.html#toArray-T:A- with that array.

Can this issue be fixed?
I'll be glad to create a PR for this.

@Anmol-Singh-Jaggi , I think the workaround could be this:

    io.vavr.collection.List<Task<MyObject>> vavrList = io.vavr.collection.List.of(t1, t2);
    Task.par(vavrList.asJava());

(see https://www.javadoc.io/doc/io.vavr/vavr/0.9.0/io/vavr/collection/List.html#asJava-- )

Yes we have been converting vavr list to java list manually.
But it would be great it parseq could support vavr lists natively to avoid the unnecessary conversion to java list.