Beware of mvn war:inplace
So hopefully I can save somebody else four hours of frustrating, hair-tearing
debugging... a few days ago I had to make a minor change to one of the webapps
I maintain and redeploy it. I hadn't touched it in a while, but since I'm of
course using Maven for build automation, I made the change,
ran a mvn clean install and pushed the new .war
out to my Tomcat cluster. I went to verify the change and - nothing. Hm.
I must have overlooked something in the
deployment step. So I did it again, being very careful to ensure that I had
built from the correct directory, deployed what I had built... and still,
same error. How strange.
I stared at the source directory. Was I in the right source directory? Check.
Did I deploy the right .war? Check. I re-ran mvn clean by itself
and verified that the target directory got wiped out. I ran
mvn install and verified that the target directory
had been re-created with new artifacts. I deployed. I checked the timestamps
on the deployed artifact. Still, same error.
Now, this is getting frustrating. I copied the .war into /tmp
and ran javap -c on the .class file to see exactly
what was deployed. And, sure enough, what I had deployed did not
include my fix. So, I triple checked that the .war that I had
uploaded was the same one I had built. The timestamps matched. The file sizes
matched. The MD5 checksum matched. It was the same file. So I decompiled
the byte code on the artifact I had built. And lo and behold, I had built the
old, unchanged code!
Well, now, the only way this could happen would be if I was building some
old branch or something. Nope, src/main/java contained the code
I was building. I rebuilt
and decompiled the bytecode in target/main/classes . The
decompiled byte code matched what I expected from the source code. So let
me get this straight. target/main/classes contained my corrected
code. The .war was being re-created on each build. But it
contained the old code.
What. The. Hell. I ran mvn clean . I verified that the
"target" directory
was gone. Gone, gone, gone. I built and installed the package again. I
looked at the target directory. It was new. Brand new. I checked the new
.war, exploding and decompiling the contents again. It had built the old
code.
However, there was an overlooked clue in mvn's output (you know, that output
that you're supposed to be paying attention to...?)
[INFO] Processing war project
[INFO] Copying webapp resources [/Users/joshuadavies/devl/prod/app/src/main/webapp]
[INFO] Webapp assembled in [1428 msecs]
Now, of course, it's supposed to do that - that's where it gets
web.xml from. But it triggered a memory from a while back...
see, I had been working with a designer who needed to be able to style the
.jsp artifacts in the project. Since he wasn't going to be
making any code changes, it seemed like a lot of overhead for him to have to
redeploy the project every time he wanted to make a change. So I did a little
bit of research and discovered mvn war:inplace . This builds an
exploded .war right in src/main/webapp for you —
you can then point a local Tomcat instance to that directory and make
(versionable) changes that are reflected in your running instance right away.
This is nice, because you get the software engineering benefits of version
control and build automation with a sped-up development cycle.
Well, since I'm the paranoid sort — and most of the changes I need to
make are in servlet classes anyway, I re-build and re-deploy after
each change, so once I had discovered mvn war:inplace , I showed
him how to use it and went on with my development effort. What I didn't
realize is that mvn clean doesn't remove that new
src/main/webapp/WEB-INF/classes directory! So if you run
mvn war:inplace make a change, and then run
mvn clean install , Maven will dutifully compile all of your code,
generate a new target directory, create an exploded .war
in there (with the new code!), and then create a deployable artifact that includes
the old build.
This seems like an oversight in the mvn war goal to me.
As it turns out, there's a
fix, but it's sort of an obscure one.
If you add the following to your pom.xml :
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<filesets>
<fileset>
<directory>src/main/webapp/WEB-INF/classes</directory>
</fileset>
<fileset>
<directory>src/main/webapp/WEB-INF/lib</directory>
</fileset>
</filesets>
</configuration>
</plugin>
</plugins>
Then the mvn clean task will clean up the leftover parts of
mvn war:inplace each time it's run.
Add a comment:Completely off-topic or spam comments will be removed at the discretion of the moderator. You may preserve formatting (e.g. a code sample) by indenting with four spaces preceding the formatted line(s) |
I'm the author of the book
"Implementing SSL/TLS Using Cryptography and PKI".
Like the title says, this is a from-the-ground-up examination
of the SSL protocol that provides security, integrity and
privacy to most application-level internet protocols, most notably HTTP.
I include the
source
code to a complete working SSL implementation,
including the most popular cryptographic algorithms
(DES, 3DES, RC4, AES, RSA, DSA, Diffie-Hellman, HMAC, MD5, SHA-1,
SHA-256, and ECC), and show how they all fit together
to provide transport-layer security.
Joshua Davies
Past Posts
- April 30, 2021: A Date Picker Control in Vanilla Javascript
- March 31, 2021: A Web Admin Console for Redis, Part Three
- January 27, 2021: A Web Admin Console for Redis, Part Two
- December 21, 2020: A Web Admin Console for Redis, Part One
- November 30, 2020: What is Procmail and why is it using up all my memory?
- September 30, 2020: Minimal Drag and Drop Support in Javascript
- August 31, 2020: Covariance and Contravariance in Generic Types
- July 31, 2020: How Spread Out Are the Floating Point Numbers?
- June 25, 2020: ERD Diagramming Tool, Part Three
- April 30, 2020: ERD Diagramming Tool, Part Two
- March 31, 2020: ERD Diagramming Tool, Part One
- February 28, 2020: MathJax and "t.setAttribute is not a function"
- December 30, 2019: Solving Systems of Equations with Python
- October 30, 2019: Linear Regression with and without numpy
- September 30, 2019: Reading a Parquet file outside of Spark
- August 30, 2019: UML Diagrams with MetaUML
- July 30, 2019: Clustering in Python
- June 25, 2019: A Walkthrough of a TLS 1.3 Handhsake
- May 31, 2019: A DataType Printer in Java
- April 30, 2019: A Simple HTTP Server in Java, Part 3 - Cookies and Keep Alives
- March 28, 2019: A Simple HTTP Server in Java, Part 2 - POST and SSL
- February 28, 2019: A Simple HTTP Server in Java
- January 29, 2019: Angular CLI Behind the Scenes, Part Two
- September 30, 2018: Angular CLI Behind the Scenes, Part One
- August 31, 2018: Into the MMIX MOR Instruction
- July 24, 2018: Undoing Percentage Changes in your Head
- June 30, 2018: Generating Langford Pairs in Scala
- May 25, 2018: Reflections on Three Years of Reading Knuth
- April 30, 2018: java.lang.NoSuchMethodError: org.junit.vintage. engine.descriptor.RunnerTestDescriptor. getAllDescendants
- March 30, 2018: An Excel Spreadsheet for the Academy Awards
- February 28, 2018: Git for Subversion Users
- January 31, 2018: The Evolution of AngularJS
- December 31, 2017: Numerical Integration in Python
- October 31, 2017: Gradle for Java Developers
- September 29, 2017: Reflections on another year of reading Knuth
- August 30, 2017: SSL OCSP Exchange
- July 27, 2017: A walk-through of an SSL certificate exchange
- June 30, 2017: A walk-through of an SSL key exchange
- May 31, 2017: A walk-through of the SSL handshake
- March 31, 2017: A walk-through of the TCP handshake
- February 28, 2017: The TLS Handshake at a High Level
- January 31, 2017: A Walk-through of a JWT Verification
- August 31, 2016: Reflections on a year of reading Knuth
- July 29, 2016: Matching a private key to a public key
- June 30, 2016: A Completely Dissected GZIP File
- May 31, 2016: Automatic Guitar Tablature Generator, Part 2
- April 28, 2016: Automatic Guitar Tablature Generator, Part 1
- March 31, 2016: Import an encrypted private key into a Java Key Store
- February 26, 2016: Import a private key into a Java Key Store
- January 31, 2016: Debian Linux on MacBook Pro
- December 29, 2015: Is Computer Science necessary or useful for programmers?
- November 30, 2015: Client certificate authentication vs. password authentication
- October 28, 2015: A Utility for Viewing Java Keystore Contents
- September 29, 2015: Debugging jQuery with Chrome's Developer Tools
- August 26, 2015: Getting Perl, MySQL and Apache to all work together on Mac OS/X
- July 30, 2015: Extract certificates from Java Key Stores for use by CURL
- June 29, 2015: Using the Chrome web developer tools, Part 9: The Console Tab
- May 28, 2015: Using the Chrome web developer tools, Part 8: The Audits Tab
- April 30, 2015: Using the Chrome web developer tools, Part 7: The Resources Tab
- March 30, 2015: Using the Chrome web developer tools, Part 6: The Memory Profiler Tab
- February 27, 2015: Using the Chrome web developer tools, Part 5: The CPU Profiler Tab
- January 31, 2015: Using the Chrome web developer tools, Part 4: The Timeline Tab
- December 31, 2014: Using the Chrome web developer tools, Part 3: The Sources Tab
- October 31, 2014: Using the Chrome web developer tools, Part 2: The Network Tab
- September 30, 2014: Using the Chrome web developer tools, Part 1: The Elements Tab
- August 11, 2014: Unable to find valid certification path to requested target
- June 30, 2014: Sort by a Hierarchy
- May 29, 2014: OpenSSL Tips and Tricks
- April 25, 2014: Heartbleed: What the Heck Happened
- February 28, 2014: Replace Microsoft Money with a Spreadsheet
- January 29, 2014: An Illustrated Guide to the BEAST Attack
- December 21, 2013: Where does GCC look to find its header files?
- October 24, 2013: Planning a Subversion import
- August 28, 2013: Compile and test an iOS app from the command line
- July 31, 2013: The Hidden Costs of Software Reuse
- June 26, 2013: Beware of mvn war:inplace
- May 29, 2013: Block Font Design Using Javascript
- April 4, 2013: Parsing a POM file using only SED
- February 22, 2013: Inside the PDF File Format
- December 31, 2012:How and why rotation matrices work
- November 27, 2012:Date Management in Java
- October 21, 2012:
Installing Debian Without a Network
- August 14, 2012:
My Review of Matt Neuburg's "Programming iOS 5"
- July 16, 2012:
An example OAuth 1.0 Handshake and mini-library
- May 23, 2012:
A Javascript one-liner to display cookie values
- April 27, 2012:
How SSL Certificates Use Digital Signatures
- March 29, 2012:
A breakdown of a GIF decoder
- February 15, 2012:
The design and implementation of LZW (the GIF compression algorithm)
- January 16, 2012:
Calculate the day of week of any date... in your head
- December 4, 2011:
Understanding CRC32
- October 29, 2011:
Efficient Huffman Decoding
- October 4, 2011:
Extract a private key from a Gnu Keyring file
- September 5, 2011:
From Make to Ant to Maven
- July 18, 2011:
A bottom-up look at the Apache configuration file
- July 6, 2011:
Fun with the HTML 5 Canvas Tag
- Jun 16, 2011:
Pain and disfiguration upon all comment spammers
- May 31, 2011:
Use of RSSI and Time-of-Flight Wireless Signal Characteristics for Location Tracking
- May 7, 2011: Implementing SSL
- Apr 24, 2011: Dissecting the GZIP format
|