I've done a fair bit with Spring in Java. Unfortunately the promises seem to fall short of delivering as your application scales up in complexity. I've experienced a number of problems with annoying little bugs and some odd brick walls with transaction management (between JMS/Hibernate).
I'd rather build something with Java EE6 if I had the choice now, or ASP.Net MVC+WCF+NHibernate if I had the choice of platform.
1) WELD CDI has no good testing story. The only option that allows CDI to work is to use Arquillian which deploys and undeploys an entire WAR for every test class, it other words it takes hours to run integration tests. Unit tests are livable using Mokito and its ability to mock injections.
2) JSF + WELD have holes between there specs. CDI can manage JSF session and request scoped beans and you can use conversation scoped beans in JSF. However they never got around to figuring out view scoped beans (which IMO is one of the most useful things in JSF). As a result you have to use some third party to make them work together. There are a number of other spec holes but I'll use this one as an example.
This means using SEAM 3 or CODI CDI extensions to fill the gaps. I went with SEAM 3 as it theoretically had a good lineage given that a lot of what was done in SEAM 2 ended up being the EE6 spec. What the SEAM 3 project did however, was to write a half assed version of all their extensions, then summarily announced they were all ditching the project to go work on Apache Deltaspike, which is basically the same extensions with a different name. Currently the SEAM 3 extensions are in various states of broken depending on the extension and your use case, and of course Delta Spike isn't ready yet (still in Apache Incubator). I've removed most of SEAM 3 from my app at this point, the remaining module is SEAM Faces which is unfortunately plugging the hole in JSF View Scope working with WELD. Also unfortunate is that there is and has been a bug in SEAM Faces for months now that causes the data JSF stored in the session to be unserializable. So I'm stuck with sticky sessions.
SEAM modules also fill in the hole with Hibernate's stupid session management, i.e. opening a transaction in the RENDER_RESPONSE phase so lazy loading works.
Several times now I've run into bugs, gone to research them and found they weren't fixed because people from the involved modules were arguing over the EE6 spec.
I could probably yap for awhile here but It may be easier to say this, I started my current product last April(2011), it started as a "pure" EE6 app. I ran into so many EE6 bugs and just pure stupidity in places that I've been moving away from it ASAP. I've replaced Hibernate with Ebean, ditched 90% of SEAM, setup an API with Jersey/Jackson and we're now pushing all front end stuff to Rails or Backbone apps which just talk to the API.
I'd never write another webapp with EE6. Jetty/Jersey/Jackson is great for web services, especially with groovy. If you need to handle the front end tasks, use play or grails.
> I'd never write another webapp with EE6. Jetty/Jersey/Jackson is great for web services, especially with groovy. If you need to handle the front end tasks, use play or grails.
Play or Grales might be just as bad as EE6. Do you also have similarly intensive experience with Play and/or Grales since April 2011 that you can compare with?
To be honest if I were starting again today I would not have used java except for performance limited jobs exposed as web services. Even those I would be tempted to write in Go. I may have used it for interfacing with some of the archaic XML APIs I have to interface with, JAXB does a good job with dealing with shenanigans in the format I've found.
That said to get to your question, I don't have experience with either at the same scale as the EE6 app. I have fiddled with both some to get a feel as I was deciding what the path away from the EE6 stuff I would take. I have ditched hibernate for Ebean (Ebean is the ORM that comes with Play). I've also started writing most of the controllers in Groovy, which comes from messing with grails. Both these changes have been awesome and significantly simplified the project.
Oddly I was just at a JUG last night about Arquillian. To your point #1, we were led to believe that the deployment was a micro deployment and you only deployed the bits that you were testing, so that this was "quick". Not so?
In theory your right, you put whatever you want in the WAR it deploys.
The entire point of Arquillian is to test in a live container, which means using it for things that will interact with the container services. They love to put up examples of stuffing 3 classes into a war and testing it, to which I say, why? It makes sense if your testing a CDI extension (who incidentally seem to be the only people using Arquillian). If I wanted to test 3 classes from my app I'd mock the injects with mockito. Its far faster and easier to use mockito to inject instances, especially since mockito can instrument those injections allowing you to assert method call information.
Where this all falls apart is where Arquillian should shine: integration tests. e.g. put up a functional JSF controller/view and fire requests at it with JSFUnit. You now have to package up enough stuff into your war to get a functional JSF environment running. Arquillian doesn't help you at all to figure out what dependencies you need to include to just get JSF running. As a result you end up playing games trying to get the WAR to include what it needs to run which can be much harder than it sounds due to the way much of the EE6 stack is layered and intertwined. You end up having to include a ludicrous amount of stuff to get JSF running. Or you just say 'fuck it' and tell Arquillian to include your entire pom and get a huge deploy. On top of this is managing your own dependencies. Is your view modularized and using 5 different sub views and supporting controllers (and associated helpers?). Its all up to you to track and manage this. Its like being thrown back into a world without maven for every single test case you try to setup. I found I spent more time trying to figure out what I needed to deploy than I did writing tests.
Also your completely screwed if you try to do a service layer down to database integration test and your using hibernate. Waiting for hibernate to start up on every test class is brutal. Getting rid of hibernate makes testing and many other things so much easier. If you stop to think about how much crap exists in the stack just to deal with hibernates session lifecycle and transaction requirements its amazing. In my current app I have about ~65 entity and ~70 tables, switching from Hibernate to Ebean and ditching the libraries I no longer needed to deal with hibernates session management dropped my final war size by ~15MB (40%), cut startup time in half, and allowed me to remove over a thousand lines of code.
Comments
I've done a fair bit with Spring in Java. Unfortunately the promises seem to fall short of delivering as your application scales up in complexity. I've experienced a number of problems with annoying little bugs and some odd brick walls with transaction management (between JMS/Hibernate).
I'd rather build something with Java EE6 if I had the choice now, or ASP.Net MVC+WCF+NHibernate if I had the choice of platform.
> I'd rather build something with Java EE6 if I had the choice now
Don't, its a nightmare.
Thanks for the heads up :) anything in particular that kills it for you?
1) WELD CDI has no good testing story. The only option that allows CDI to work is to use Arquillian which deploys and undeploys an entire WAR for every test class, it other words it takes hours to run integration tests. Unit tests are livable using Mokito and its ability to mock injections.
2) JSF + WELD have holes between there specs. CDI can manage JSF session and request scoped beans and you can use conversation scoped beans in JSF. However they never got around to figuring out view scoped beans (which IMO is one of the most useful things in JSF). As a result you have to use some third party to make them work together. There are a number of other spec holes but I'll use this one as an example.
This means using SEAM 3 or CODI CDI extensions to fill the gaps. I went with SEAM 3 as it theoretically had a good lineage given that a lot of what was done in SEAM 2 ended up being the EE6 spec. What the SEAM 3 project did however, was to write a half assed version of all their extensions, then summarily announced they were all ditching the project to go work on Apache Deltaspike, which is basically the same extensions with a different name. Currently the SEAM 3 extensions are in various states of broken depending on the extension and your use case, and of course Delta Spike isn't ready yet (still in Apache Incubator). I've removed most of SEAM 3 from my app at this point, the remaining module is SEAM Faces which is unfortunately plugging the hole in JSF View Scope working with WELD. Also unfortunate is that there is and has been a bug in SEAM Faces for months now that causes the data JSF stored in the session to be unserializable. So I'm stuck with sticky sessions.
SEAM modules also fill in the hole with Hibernate's stupid session management, i.e. opening a transaction in the RENDER_RESPONSE phase so lazy loading works.
Several times now I've run into bugs, gone to research them and found they weren't fixed because people from the involved modules were arguing over the EE6 spec.
I could probably yap for awhile here but It may be easier to say this, I started my current product last April(2011), it started as a "pure" EE6 app. I ran into so many EE6 bugs and just pure stupidity in places that I've been moving away from it ASAP. I've replaced Hibernate with Ebean, ditched 90% of SEAM, setup an API with Jersey/Jackson and we're now pushing all front end stuff to Rails or Backbone apps which just talk to the API.
I'd never write another webapp with EE6. Jetty/Jersey/Jackson is great for web services, especially with groovy. If you need to handle the front end tasks, use play or grails.
> I'd never write another webapp with EE6. Jetty/Jersey/Jackson is great for web services, especially with groovy. If you need to handle the front end tasks, use play or grails.
Play or Grales might be just as bad as EE6. Do you also have similarly intensive experience with Play and/or Grales since April 2011 that you can compare with?
To be honest if I were starting again today I would not have used java except for performance limited jobs exposed as web services. Even those I would be tempted to write in Go. I may have used it for interfacing with some of the archaic XML APIs I have to interface with, JAXB does a good job with dealing with shenanigans in the format I've found.
That said to get to your question, I don't have experience with either at the same scale as the EE6 app. I have fiddled with both some to get a feel as I was deciding what the path away from the EE6 stuff I would take. I have ditched hibernate for Ebean (Ebean is the ORM that comes with Play). I've also started writing most of the controllers in Groovy, which comes from messing with grails. Both these changes have been awesome and significantly simplified the project.
Oddly I was just at a JUG last night about Arquillian. To your point #1, we were led to believe that the deployment was a micro deployment and you only deployed the bits that you were testing, so that this was "quick". Not so?
In theory your right, you put whatever you want in the WAR it deploys.
The entire point of Arquillian is to test in a live container, which means using it for things that will interact with the container services. They love to put up examples of stuffing 3 classes into a war and testing it, to which I say, why? It makes sense if your testing a CDI extension (who incidentally seem to be the only people using Arquillian). If I wanted to test 3 classes from my app I'd mock the injects with mockito. Its far faster and easier to use mockito to inject instances, especially since mockito can instrument those injections allowing you to assert method call information.
Where this all falls apart is where Arquillian should shine: integration tests. e.g. put up a functional JSF controller/view and fire requests at it with JSFUnit. You now have to package up enough stuff into your war to get a functional JSF environment running. Arquillian doesn't help you at all to figure out what dependencies you need to include to just get JSF running. As a result you end up playing games trying to get the WAR to include what it needs to run which can be much harder than it sounds due to the way much of the EE6 stack is layered and intertwined. You end up having to include a ludicrous amount of stuff to get JSF running. Or you just say 'fuck it' and tell Arquillian to include your entire pom and get a huge deploy. On top of this is managing your own dependencies. Is your view modularized and using 5 different sub views and supporting controllers (and associated helpers?). Its all up to you to track and manage this. Its like being thrown back into a world without maven for every single test case you try to setup. I found I spent more time trying to figure out what I needed to deploy than I did writing tests.
Also your completely screwed if you try to do a service layer down to database integration test and your using hibernate. Waiting for hibernate to start up on every test class is brutal. Getting rid of hibernate makes testing and many other things so much easier. If you stop to think about how much crap exists in the stack just to deal with hibernates session lifecycle and transaction requirements its amazing. In my current app I have about ~65 entity and ~70 tables, switching from Hibernate to Ebean and ditching the libraries I no longer needed to deal with hibernates session management dropped my final war size by ~15MB (40%), cut startup time in half, and allowed me to remove over a thousand lines of code.
Thank you for your time on this response. It's a lot to digest!
Thanks for the detailed response. Much appreciated.
I think I will avoid as well then.