We recently moved an application to a new server, with an updated installation of Java 8. It didn’t take long to discover that Amazon S3 accesses were failing with an authentication error, and it didn’t take much longer to discover that this problem was already fixed in the version of the AWS Java SDK we were using.
com.amazonaws.services.s3.model.AmazonS3Exception: AWS authentication requires a valid Date or x-amz-date header
The real problem was that we had many dependencies on different versions of Joda Time, and AWS had lost the battle - we were actually running Joda Time 2.0.
It was time to stop this happening again, with the Maven Enforcer Plugin. It’s possible to fail the build if we ever reference two versions of the same dependency:
I’m integrating Quartz scheduling into an application, and was looking for an annotation based approach to configuration. I quickly found the SivaLabs implementation, which works for Quartz 1.8. I’ve made a few changes to use this with Spring 4.1.4 and Quartz 2.2.3.
The custom annotation remains the same:
The major change is that I have replaced the ApplicationListener class with a bean that performs a single scan of a selected package. I chose this approach because my configuration does not change once loaded, and I wanted to throw a fatal exception on any error in Quartz configuration. I’ve refactored to add each job to the scheduler as it is discovered, rather than building an intermediate list.
The CronTriggerBean and JobDetailBean from Spring 3 are gone in Spring 4. The new code builds the job using the Quartz 2 fluent builders, rather than Spring’s factory beans:
The job factory is unchanged from the original article, and the XML configuration looks like this:
At this point jobs are automatically configured as long they:
implement the Job interface
have the QuartzJob annotation
are in a package scanned by Spring, and by the QuartzJobScanner
We have a monolith. It’s not the biggest monolith, but it does contain a lot of Java libraries, managed with Maven. This week an upgrade to one package caused a distant side effect.
Our monolith is a web application, and uses an embedded Jetty server. It also uses Jasper reports, compiling jrxml files on demand. This week, our builds stopped compiling reports, with an exception that Jasper could not find javac. The first thought was that somebody had changed the server install from a JDK to a JRE, leaving the compiler unavailable. But after installing the latest JDK, and checking the system path, the error changed:
net.sf.jasperreports.engine.JRException: Errors were encountered when compiling report expressions class file:
C:\Users\adrian\Workspaces\Customer\App\App-Web\j491845presale_seller_1464295746680_612367.java:227: error: cannot find symbol
value = DATEFORMAT(((java.sql.Timestamp)field_sale_start.getValue()), "dd/MM/YYYY"); //$JR_EXPR_ID=2$
symbol: method DATEFORMAT(Timestamp,String)
location: class j491845presale_seller_1464295746680_612367
As jasperreports-functions-5.6.1.jar was in the classpath, there was clearly another problem. Why was Jasper searching for javac at all, when Eclipse JDT was available?
The next step was to go through our commits to find the point where things went wrong. It didn’t take long to discover the breakage was caused by an upgrade from Jetty 9.0 (2013) to Jetty 9.3 (2016). But how had this broken Jasper?
Stepping through Jasper initialisation reveals that Jasper attempts to load org.eclipse.jdt.internal.compiler.env.AccessRestriction in order to discover which version of JDT is present. This attempt fails, even though the class is present on the classpath.
This turned my debugging attention to the classloader. Jetty includes a WebAppClassloader, and setting a breakpoint in its loadClass method revealed that the JDT class was identified as a server class. Knowing this cause, it didn’t take long to find the commit that broke Jasper on Github.
As our application uses Jetty as an embedded web server, I disabled the WebAppClassloader like this, and Jasper reports worked again: