DaedTech

Stories about Software

By

JUnit Revisited

Just as a warning, in this short post, I’m going to be writing unit tests that verify that primitives in Java do what they should and basically that gravity is still turned on. The reason for that is that I’d like to showcase some new Java unit testing goodies I’ve recently discovered since coming back into the Java fold a little here and there lately. I firmly believe that the more conversationally readable the contents of unit tests are, the more effective they will be at defining functional and internal requirements as well as showcasing the behavior of the system.

@Test
public void two_ints_are_equal() {
int x = 4;
int y = 4;
assertThat(x, is(y));
}

Coming from the .NET world and using MSTest, I’m used to semantics of Assert.AreEqual<int>(x, y) where, by convention, the “control” or expected value goes on the left and the actual value goes on the right. This is a compelling alternative in that it reads like a sentence, which is always good. The MSTest version reads “Are equal x and y” whereas this reads “x is y.” The less it reads like Yoda is talking, the better. So what enables this goodness?

import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.matchers.JUnitMatchers.*;

The first import gives you assertThat(), obviously. assertThat() as shown above takes two parameters (there is an overload that takes a string as an additional parameter to let you specify a failure message): a generic type for the first parameter, and a “matcher” for the second parameter. Matchers perform evaluations on types and can be chained together in fluent fashion to allow construction of sentences that flow. For instance, you can chain the is() matcher and the not() matcher to get the following test:

@Test
public void two_ints_are_not_equal() {
int x = 4;
int y = 5;
assertThat(x, is(not(y)));
}

This really just scratches the surface and there are lots of additional matchers from hamcrest as well. You can even extend the functionality by defining your own matchers to cater to the ubiquitous language of the domain that you’re using. This just barely scratches the surface, but if you’re a java developer and haven’t given these a look, I’d suggest doing so. If you’re a .NET developer, it’s worth taking a peek at what’s going on elsewhere and perhaps defining your own such constructs if you’re feeling ambitious or looking for existing ones. In fact, if you know of good ones, please post ’em — I always like seeing what’s out there.

By

Programatically Filling Out PDFs in Java

I just got done dealing with an interesting problem. I had one of those PDFs that’s a form you can fill out and was tasked with programatically filling it out. So, I busted out my google-fu and came across PDFBox. It’s a handy and fairly no-nonsense little utility not just for filling out forms, but for manipulating PDFs in general. I had no idea something like this existed (mainly because I’d never really thought about it).

I downloaded the jar for PDFBox and wrote a simple class to test out my theory. In setting up the class and poking around randomly in the documentation, I saw that the main object of interest was a PDDocument. So, I set about instantiating one and discovered that you needed to use something called a COSDocument, which took something called a RandomAccess (not the standard version of the file, but a special version from PDFBox), and then my eyes started to cross and I pulled back and discovered that this is really what I want:

private static PDDocument _pdfDocument;

private static void populateAndCopy(String originalPdf, String targetPdf) throws IOException, COSVisitorException {
	_pdfDocument = PDDocument.load(originalPdf);
	
	_pdfDocument.save(targetPdf);
	_pdfDocument.close();
}

Much easier. Now, as I got down to business of trying this out, I discovered via runtime exception that I needed two external dependencies. One was apache commons logging and the other was something called fontbox that was right there along with the PDFBox download, but I ignored in the beginning. Probably with this code alone you wouldn’t necessarily hit both of those problems, but you will eventually, so better to add those jars right up front.

So far I was able successfully to open a PDF and save it as another file, which isn’t exactly a new capability for any programming language with file I/O, so I added something a little more concrete to the mix:

private static void populateAndCopy(String originalPdf, String targetPdf) throws IOException, COSVisitorException {
	_pdfDocument = PDDocument.load(originalPdf);
	
	_pdfDocument.getNumberOfPages();
	
	setField("SomeFieldName", "SomeFieldValue");
	_pdfDocument.save(targetPdf);
	_pdfDocument.close();
}

Lo and behold, liftoff. I actually got the right number of pages in the document. Now I was getting somewhere. Time to get down to the real business. I did this by going to the “Cookbook” section of the project and seeing what was under form generation. Seeing that this just took me to the javadoc for examples, I went and downloaded the example code and pasted it into my project (modifying it to conform to the Egyptian-style braces. In this fashion, I had a method that would print out all of the fields in the PDF as well as a method that would let me set fields by name. When I ran the one that printed out all of the fields, I got a runtime exception about some deprecated method and I discovered that in the source code for that method, it just threw an exception. Presumably, the written examples predated some change that had deprecated that method — deprecated it with extreme prejudice!

Well, I’d like to say that I fought the good fight, but I didn’t. I just deleted the offending call since it was just writing to console. So here is the end result of that effort:

public class Populater {

	private static PDDocument _pdfDocument;
	
	public static void main(String[] args) {
		
		String originalPdf = "C:\\blah\\blah\\input.PDF";
		String targetPdf = "C:\\blah\\blah\\input.PDF";
		
		try {
			populateAndCopy(originalPdf, targetPdf);
		} catch (IOException | COSVisitorException e) {
			e.printStackTrace();
		}
		
		System.out.println("Complete");
	}

	private static void populateAndCopy(String originalPdf, String targetPdf) throws IOException, COSVisitorException {
		_pdfDocument = PDDocument.load(originalPdf);
		
		_pdfDocument.getNumberOfPages();
		//printFields();  //Uncomment to see the fields in this document in console
		
		setField("SomeFieldName", "SomeFieldValue");
		_pdfDocument.save(targetPdf);
		_pdfDocument.close();
	}
	
    public static void setField(String name, String value ) throws IOException {
        PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
        PDAcroForm acroForm = docCatalog.getAcroForm();
        PDField field = acroForm.getField( name );
        if( field != null ) {
            field.setValue(value);
        }
        else {
            System.err.println( "No field found with name:" + name );
        }
    }

    @SuppressWarnings("rawtypes")
	public static void printFields() throws IOException {
        PDDocumentCatalog docCatalog = _pdfDocument.getDocumentCatalog();
        PDAcroForm acroForm = docCatalog.getAcroForm();
        List fields = acroForm.getFields();
        Iterator fieldsIter = fields.iterator();

        System.out.println(new Integer(fields.size()).toString() + " top-level fields were found on the form");

        while( fieldsIter.hasNext()) {
            PDField field = (PDField)fieldsIter.next();
               processField(field, "|--", field.getPartialName());
        }
    }
    
    @SuppressWarnings("rawtypes")
	private static void processField(PDField field, String sLevel, String sParent) throws IOException
    {
        List kids = field.getKids();
        if(kids != null) {
            Iterator kidsIter = kids.iterator();
            if(!sParent.equals(field.getPartialName())) {
               sParent = sParent + "." + field.getPartialName();
            }
            
            System.out.println(sLevel + sParent);
            
            while(kidsIter.hasNext()) {
               Object pdfObj = kidsIter.next();
               if(pdfObj instanceof PDField) {
                   PDField kid = (PDField)pdfObj;
                   processField(kid, "|  " + sLevel, sParent);
               }
            }
         }
         else {
             String outputString = sLevel + sParent + "." + field.getPartialName() + ",  type=" + field.getClass().getName();
             System.out.println(outputString);
         }
    }
}

Going forward, I’ll certainly factor this into a new class and probably extract some methods and improve warning avoidance, but that’s the gist of it. This didn’t exactly take a long time, but it probably could have gone quicker if I’d known a little more up-front and had all example code in one place. Hopefully it helps you in that capacity.

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.

By

Faking Tomcat Support in IntelliJ IDEA Community Version

A while back, I blogged about my switch from Eclipse to the community (free) version of IntelliJ IDEA. After that, I went on a number of trips out of town, felt out the job market a bit, and generally engaged in a series of activities that have kept me too busy to work on my home automation. In the last week, however, that’s changed and I’ve revisited it.

The first thing that I decided to do was play with Ant a bit to create an environment where I could build and run the application locally. I’m in a bit of a catch-22 with IntelliJ at the moment. I might be interested in purchasing the Ultimate Edition, but not before I take it out for a few months and kick the tires. But, in order to do that without pain, I kind of need the server support for what I’m doing, which is only available in Ultimate. So, I’m faking it. I created the following Ant build.xml:




    
        
            
        
    

    
        
        
    

    
        
            
        
    

    
        
            
            
            
            
        
        
        
        
            
        
    

    
        
        
    


The other build targets are somewhat standard, if memory serves (I was never particularly adept with Ant, and now I’m several years removed from using it). But, the interesting one is the “war” target, which I’m probably going to rename here shortly. This first compiles the project into a deployable WAR file and plops it into the local Tomcat webapps directory, which is where the it needs to be for me to run it locally in a browser.

With that in place, I’ve added the next line, which starts the web server. In the way I invoke it, a command window pops up, and I can stop the server by closing it. Once the server is started, I launch chrome to the URL where the application will be. This works, but I’d like to refine it a bit. Here are some things that I think should happen:

  1. First of all, DRY isn’t just for code. I’m defining “Daedalus.war” and “http://localhost:8080/Daedalus” and if I decide to change the deployable name, there are two failure points. I’m going to correct that.
  2. And, as long as I’m changing the “destfile” property of the war file, I might as well define a descriptive constant for the Tomcat webapps directory.
  3. Secondly, “browser” isn’t a particularly good property name for Chrome, so I’m going to rename it.
  4. Along those same lines, I’m going to create a property for Internet Explorer as well
  5. I’m also going to create build targets for chrome and internet explorer so that I can choose which one to run without modifying the build.xml file.
  6. Finally, I’m going to decouple the building of the War from the starting of the server and decouple both of those from opening a browser. That way I won’t have to repeat myself in the internet explorer and chrome versions.

Here’s what it looks like now:




    
    
    
    
    
    

    

    
        
            
        
    

    
        
        
    

    
        
            
        
    

    
        
            
            
            
            
        
    

    
        
    

    
        
            
        
    

    
        
            
        
    

    
        
        
    


So, I’m relatively pleased with this for the time being. Two small caveats with this approach, though. The first is that I don’t really like duplicating the “http://localhost:8080” as the server’s localhost, but I’m unlikely ever to change this, and if I abstract that out to a constant, it fails for some reason that I haven’t seriously looked into (and realistically, probably won’t for now). The second is that I start the server, but you have to manually stop it. That’s kind of ick, but I’ll live with it for now. If/when I put together a better scheme, I’ll post it.

But, with this you get support for Tomcat with IntelliJ IDEA community edition. It’s obviously not nearly as snazzy as having it integrated to the IDE, but if you’re in my boat, this is nice. I’ve automated most of the stuff that I’d rely on the IDE to do, and I’ve done it without spending a few hundred dollars I’m not yet sure I can justify. Cheers if this helps you.

By

IntelliJ IDEA: Saying Goodbye to Eclipse

I received a recommendation from Ted Young recently to try a switch to IntelliJ IDEA as an alternative to Eclipse IDE. I’ve been using Eclipse for years, but figured I’d give this tool a try, as it’s brought to you by the clever folks that make Resharper. Uncle Bob uses it in his series of Clean Code videos as well. I’ve been watching these lately, and his fluency with that IDE is making me long for something a little more… polished than Eclipse. I guess I’m spoiled by Visual Studio.

Anyway, I’ve installed the Community version of IntelliJ. Over the weekend, I spent a few hours porting my home automation project, Daedalus, to be usable by IntelliJ. Mostly, this involved turning it into a Maven project, and then ironing out a handful of miscellaneous details and quirks. I’m already much happier with this IDE than I was with Eclipse.

For starters, the Intelli-Sense (or whatever it’s called) is vastly superior to Eclipse. The static analysis for things like non-compiling code is also much snappier and prettier. And, beyond that, little things do what I’m used to from Visual Studio (e.g. ctrl-tab between code files). It’s weird, but a few things like that here and there really add up to being happier with the user experience. Using IntelliJ feels like coming home, which is impressive, since I’ve never used it (and I don’t even use ReSharper). Color me impressed.

Here is a handful of other miscellaneous observations so far:

  • Ctrl-W and Ctrl-Shift-W widen and narrow selected scope, respectively (equivalent of the numpad + and – in CodeRush).
  • Getting my black background seemed pretty tedious. I didn’t discover until the end that if I set some high level setting with black background, that mostly became default.
  • On the flip side, the color scheme in there is awesome – I can vary RGB ratios and darkness independently, meaning I can keep the default color scheme, but make all the foreground colors a lot lighter so they show up on black.
  • If you download the Community (read: free) version, bear in mind that you get no server integration. It took me a long time to figure out that I couldn’t integrate Tomcat as that’s only for the pay-to-play version
  • The last bullet isn’t a major hindrance. I just set up an Ant build to deploy a WAR file and set the Ant build up to run after successful compile when I want to deploy. The only thing I lose is the ability to start Tomcat in the IDE and browse in the IDE but both of those were pretty flaky in Eclipse anyway. Keeping a browser window open isn’t the end of the world.
  • When I go to commit to SVN, a window pops up with code analysis messages, giving me what I assume is the Java equivalent of StyleCop or FX Cop. This is pretty awesome since my idiomatic Java is pretty rusty. I imagine this will help shake off some of that rust.
  • Still haven’t worked out all of the shortcuts for running tests in TDD. Options seem better than Eclipse, but I still have to tame them.
  • The project/module definition in place of Eclipse’s workspace/project definition is a little odd, but whatever.

That’s about it, so far. I’ll probably have more posts to add as I go. I wish I had documented and blogged about the conversion from Eclipse, as that was relatively straightforward, but with a few gotchas, since I didn’t have Maven set up for Eclipse and I did have the Spring/Tomcat/Jstl dependencies. Thing is, I kind of started off not thinking I was actually going to switch and just doing some exploratory puttering, so I didn’t get into the documentation mindset until it was too late. Oh well, c’est la vie. If anyone’s curious about anything I did, please feel free to comment or shoot me an email.

At any rate, I think I’m probably going to close the books on Eclipse. I suspect that my only future debate here is whether or not to upgrade to the paid Ultimate version of IntelliJ. Given that I alternate between .NET and Java, the relative synergy between IntelliJ and Visual Studio is simply too huge an advantage to pass up. I realize that Eclipse probably has a richer plugin library, but to be honest, my opinion of Eclipse has always more or less been “meh, it works, I guess”, rather than “ooh, this is nice!” After even just a few days with IntelliJ, it’s hard to see myself going back.

By

Recognizing Test Smells

Tonight, I was plodding through the process of getting to know MongoDB and its java driver, TDD style. This is an interesting experience, as most of one’s development is going to involve technologies with which one is familiar and working out designs. This is classic problem isolation — all of your tools are familiar, and you have only to work out the design itself. In this case, I have two problems – the technology and the design aren’t familiar. In situations like this, it’s even more important to follow your nose when it comes to smells in code or tests, as you’re really flailing around in the dark. These may be the only things that guide a technology initiate to good practice short of taking a class or reading some books (and even then, they’re important, because you can only learn so much without getting your hands dirty.

Read More