Official supercsv dozer example does not work with Play — Play 2.1.1, Java

867 views Asked by At

Update:

Now I found out something very strange, it works when i put the compiled test classes directly into the "super-csv-dozer-2.1.0.jar" with the same structure as in the svn repo. But as soon as i use my own package it wont work. I always used the entire path like this: myPackage.csv.SurveyResponse.class What am i missing? and why does it work in a normal Java Project but not in a Play Project? I also tried it outside of eclipse in a different directory and dont have any checkouts from the svn repo that could confuse the paths. Another thing i tried is to put the Writing.class into adifferent package but didnt help.

Original qustion:

Im trying to use SuperCSV with Dozer in a Play Project. The official supercsv sample works fine in a separate Java Project. But when I put the code and the needed SuperCSV Jars in a freshly created Play project I always get a ClassNotfoundException for SurveyResponse.class in this line of code: beanWriter.configureBeanMapping(myPackage.csv.SurveyResponse.class, FIELD_MAPPING);

Here a screenshot of my project structure: http://oi44.tinypic.com/mrqp7s.jpg

I made sure that all the JARS are available, I put them unmanaged into the /lib folder, they are available in eclipse and no errors appear during compilation. I debugged the code and the SurveyResponse.class is found and the beanWriter is initialized. So somehow Play must do some magic in the background to trigger this bug. What could play be doing in the background to possibly trigger such odd behavior? What could I try to do to fix this?

Changes I made to the sample so it works with Play: I used exactly the same code as the offical supercsv example. The only change i did is remove the Writing.main(..) method and set the methods Writing.writeWithDozerCsvBeanWriter() and Writing.partialWriteWithCsvDozerBeanWriter() to public,so it can be accessed from the Application controller. And of course I changed the package name in all classes to package myPackage.test;

Links to sample: See in the comment, i cant add more than 2 links because of low reputation.

Controller:

public class Application extends Controller {
    public static Result index() throws Exception  {
        Writing.writeWithDozerCsvBeanWriter();
        Writing.partialWriteWithCsvDozerBeanWriter();
        return ok(index.render("Your new application is ready."));
    } 
}

Code that triggers error in Writing class:

ICsvDozerBeanWriter beanWriter = null;
    try {
        beanWriter = new CsvDozerBeanWriter(new FileWriter("target/writeWithCsvDozerBeanWriter.csv"),
            CsvPreference.STANDARD_PREFERENCE);
        
        // configure the mapping from the fields to the CSV columns
        //Here the exception occures:
        beanWriter.configureBeanMapping(myPackage.csv.SurveyResponse.class, FIELD_MAPPING);

Stack trace:

play.api.Application$$anon$1: Execution exception[[MappingException: java.lang.ClassNotFoundException: myPackage.test.SurveyResponse]]
    at play.api.Application$class.handleError(Application.scala:289) ~[play_2.10.jar:2.1.1]
    at play.api.DefaultApplication.handleError(Application.scala:383) [play_2.10.jar:2.1.1]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anon$2$$anonfun$handle$1.apply(PlayDefaultUpstreamHandler.scala:144) [play_2.10.jar:2.1.1]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anon$2$$anonfun$handle$1.apply(PlayDefaultUpstreamHandler.scala:140) [play_2.10.jar:2.1.1]
    at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.1]
    at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.1]
    at play.api.libs.concurrent.PlayPromise$$anonfun$extend$1$$anonfun$apply$1.apply(Promise.scala:104) [play_2.10.jar:2.1.1]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) [scala-library.jar:na]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) [scala-library.jar:na]
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) [na:1.6.0_37]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) [na:1.6.0_37]
    at java.lang.Thread.run(Unknown Source) [na:1.6.0_37]
org.dozer.MappingException: java.lang.ClassNotFoundException: myPackage.test.SurveyResponse
    at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82) ~[dozer-5.4.0.jar:na]
    at org.dozer.util.DefaultClassLoader.loadClass(DefaultClassLoader.java:38) ~[dozer-5.4.0.jar:na]
    at org.dozer.util.MappingUtils.loadClass(MappingUtils.java:224) ~[dozer-5.4.0.jar:na]
    at org.dozer.loader.DozerBuilder$MappingBuilder.classA(DozerBuilder.java:129) ~[dozer-5.4.0.jar:na]
    at org.dozer.loader.api.BeanMappingBuilder.mapping(BeanMappingBuilder.java:72) ~[dozer-5.4.0.jar:na]
    at org.dozer.loader.api.BeanMappingBuilder.mapping(BeanMappingBuilder.java:67) ~[dozer-5.4.0.jar:na]
    at org.supercsv.io.dozer.CsvDozerBeanWriter$MappingBuilder.configure(CsvDozerBeanWriter.java:178) ~[super-csv-dozer-2.1.0.jar:na]
    at org.dozer.loader.api.BeanMappingBuilder.build(BeanMappingBuilder.java:42) ~[dozer-5.4.0.jar:na]
    at org.dozer.DozerBeanMapper.addMapping(DozerBeanMapper.java:258) ~[dozer-5.4.0.jar:na]
    at org.supercsv.io.dozer.CsvDozerBeanWriter.configureBeanMapping(CsvDozerBeanWriter.java:91) ~[super-csv-dozer-2.1.0.jar:na]
    at myPackage.test.Writing.writeWithDozerCsvBeanWriter(Writing.java:88) ~[na:na]
    at controllers.Application.index(Application.java:12) ~[na:na]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:49) ~[na:na]
    at Routes$$anonfun$routes$1$$anonfun$applyOrElse$1$$anonfun$apply$1.apply(routes_routing.scala:49) ~[na:na]
    at play.core.Router$HandlerInvoker$$anon$6$$anon$2.invocation(Router.scala:164) ~[play_2.10.jar:2.1.1]
    at play.core.Router$Routes$$anon$1.invocation(Router.scala:345) ~[play_2.10.jar:2.1.1]
    at play.core.j.JavaAction$$anon$1.call(JavaAction.scala:31) ~[play_2.10.jar:2.1.1]
    at play.core.j.JavaAction$$anon$2.apply(JavaAction.scala:74) ~[play_2.10.jar:2.1.1]
    at play.core.j.JavaAction$$anon$2.apply(JavaAction.scala:73) ~[play_2.10.jar:2.1.1]
    at play.libs.F$Promise$PromiseActor.onReceive(F.java:420) ~[play_2.10.jar:2.1.1]
    at akka.actor.UntypedActor$$anonfun$receive$1.applyOrElse(UntypedActor.scala:159) ~[akka-actor_2.10.jar:na]
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:425) ~[akka-actor_2.10.jar:na]
    at akka.actor.ActorCell.invoke(ActorCell.scala:386) ~[akka-actor_2.10.jar:na]
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:230) ~[akka-actor_2.10.jar:na]
    at akka.dispatch.Mailbox.run(Mailbox.scala:212) ~[akka-actor_2.10.jar:na]
    at akka.dispatch.ForkJoinExecutorConfigurator$MailboxExecutionTask.exec(AbstractDispatcher.scala:502) ~[akka-actor_2.10.jar:na]
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262) ~[scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975) ~[scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478) ~[scala-library.jar:na]
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104) ~[scala-library.jar:na]
Caused by: java.lang.ClassNotFoundException: myPackage.test.SurveyResponse
    at java.net.URLClassLoader$1.run(Unknown Source) ~[na:1.6.0_37]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.6.0_37]
    at java.net.URLClassLoader.findClass(Unknown Source) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.6.0_37]
    at java.lang.ClassLoader.loadClass(Unknown Source) ~[na:1.6.0_37]
    at sbt.PlayCommands$$anonfun$53$$anonfun$55$$anon$2.loadClass(PlayCommands.scala:535) ~[na:na]
    at java.lang.Class.forName0(Native Method) ~[na:1.6.0_37]
    at java.lang.Class.forName(Unknown Source) ~[na:1.6.0_37]
    at org.apache.commons.lang3.ClassUtils.getClass(ClassUtils.java:823) ~[commons-lang3.jar:3.1]
    at org.apache.commons.lang3.ClassUtils.getClass(ClassUtils.java:889) ~[commons-lang3.jar:3.1]
    at org.apache.commons.lang3.ClassUtils.getClass(ClassUtils.java:872) ~[commons-lang3.jar:3.1]
    at org.dozer.util.DefaultClassLoader.loadClass(DefaultClassLoader.java:36) ~[dozer-5.4.0.jar:na]
    ... 28 common frames omitted

Extra information: I still couldnt solve the problem, but here some extra infomation to narrow down the problem: The csv header is successfully written to the file when i remove the configureBeanMapping Method call (see code below). The SurveyResponse class is working too when i do a System.out.println() on a filled SurveyResponse object (see code below). So its not a problem with the package or class name.

The modiefied Code that writes only the header:

//...more code
myPackage.csv.SurveyResponse response3 = new myPackage.csv.SurveyResponse(42, false, Arrays.asList(new Answer(1, null), new Answer(2,
    "Carl Sagan"), new Answer(3, "Star Wars")));
final List<myPackage.csv.SurveyResponse> surveyResponses = Arrays.asList(response1, response2, response3);

ICsvDozerBeanWriter beanWriter = null;
try {
    beanWriter = new CsvDozerBeanWriter(new FileWriter("target/writeWithCsvDozerBeanWriter.csv"),
        CsvPreference.STANDARD_PREFERENCE);
    
    // configure the mapping from the fields to the CSV columns
    //beanWriter.configureBeanMapping(myPackage.csv.SurveyResponse.class, FIELD_MAPPING);
    
    //Prints the value 42 successfully
    System.out.println(response3.getAge());
    
    // write the header
    beanWriter.writeHeader("age", "consentGiven", "questionNo1", "answer1", "questionNo2", "answer2","questionNo3", "answer3");

//...more code
2

There are 2 answers

1
James Bassett On

SurveyResponse and Answer are test classes of the super-csv-dozer artifact - so they aren't packaged in the distribution (i.e they're not in Maven or in the zip file on SourceForge).

You can view the test source online or checkout the SVN repo (which it sounds like you've already done) and just copy them into your Play project.

Both files are in the following directory:

supercsv/super-csv-dozer/src/test/java/org/supercsv/mock/dozer/

I'm a little curious why you're not getting a compilation error when trying to use SurveyResponse in your code. My guess is that you have the super-csv-dozer project checked out and open in your IDE and your project is finding it.

5
i.am.michiel On

From what I understand from the error, Play is trying to load the wrong class. Look at this line :

java.lang.ClassNotFoundException: org.supercsv.mock.dozer.SurveyResponse

I think that SurverResponse is one of your own project classes and not part of SuperCSV. Try to prefix it with the full path such as :

beanWriter.configureBeanMapping(whateverpackage.models.SurveyResponse.class, FIELD_MAPPING);