Friday, July 18, 2014

Eclipse for IDEA Users

If you are an IntelliJ IDEA user, there's a good chance you'll be working on a team with people who use Eclipse.   Here are some basics that will help you get the two environments working together smoothly.

Main Differences

  • The concept of a project is basically the same as it is in IDEA.
  • Eclipse has the concept of a 'workspace', which contains multiple projects.   You might make one workspace for your workplace, and another for an open source project or experiments.
  • Most of the features of IDEA exist in Eclipse, but they may be in unexpected places in the UI.  For example:
    • The plugins are installed / managed under the Help menu (and sort of under the About dialog?).  This will certainly generate a few WTFs.
    • 'Team' = version control.   That kept making me whinge.
    • Perspectives - this is kind of a 'mode' concept.   Mostly maps to the side/bottom panels in IDEA.

Install Eclipse

Best to just follow the directions.   Installation is usually not a big deal, but it's a good idea to:
  • Install the same version that everyone has on your team.
  • Install the package solution that is appropriate for the kind of development you do.   For me, this is 'Eclipse IDE for Java EE Developers'.
  • Here is an example of installing Eclipse on OSX.
    Basically: Download, unpack, drag the 'eclipse' folder into Applications (not the Eclipse application, but the whole folder).

Eclipse Plugins

  • Install plugins with Eclipse Marketplace, which is (oddly enough) under the Help menu.
  • Uninstalling plugins is done in the About Eclipse menu item, which is in the Eclipse menu on OSX.   See this wiki page for more.
  • You'll probably need to install a version control plugin (e.g. 'subclipse' if you're using subversion) and you'll need to install a dependency management plugin as well (e.g. gradle).
  • Often, plugins won't work until you delete the project from the workspace and re-import it into the workspace.

Getting Around

The Workspace


The workspace is a collections of references to project directories.   These show up as top level items once you have some in your workspace.  Eclipse will prompt you for a workspace when you start it up:

If you select 'Use this as the default', then you can easily switch workspaces using File -> Switch Workspace.

The Project Explorer will show all the projects added to the workspace.    At first there will be none, so you will typically import a project that is already on your disk.

Importing a project

This is how you get a project into the workspace, and it can be found under File -> Import, or by right clicking in the Project Explorer.  If you already have a git clone / svn checkout, the workspace will basically link to the existing location.   If you clone / checkout from version control, the default behavior is to put the files in the workspace directory.

To import a typical VCS clone/checkout that already has Eclipse project files in it, chose Generic/existing project:

The project should import successfully if you have all of the right plugins installed.   At this point you will probably want some additional views of the project: version control, etc.   This is where 'perspectives' come in.

Perspectives

Perspectives are basically different modes you can work with.   IDEA has similar windows, but it doesn't force the whole UI in to a 'mode' like Eclipse does.   To access perspectives, click the perspectives button:
The most important perspectives (from my perspective, at least ;-> ):
  • Team Synchronizing - This is similar to the VCS window in IDEA.
  • Java EE - This is basically the main project view in IDEA.

Project Files

Eclipse stores it's project information in two files .classpath, and .project, and a .settings directory.   These are roughly equivalent to the .idea directory and the IML files.

These can all be added to version control so the project can just be cloned/checked out and opened by other team members.

Things that you'll miss

So here are the things that you'll probably miss coming from IDEA:

  • Deep navigation and code 'grokking' - Eclipse just doesn't know as much about your project as IDEA does, so it can't help with some more advanced referencing and navigation.
  • Refactoring - Yeah, Eclipse has refactoring but it's very basic in terms of features and in terms of how thorough it is.   IDEA knows much more about the project, so it can refactor very completely.   With Eclipse, be prepared to complete many of the refactorings by hand.   It gets the basics done though: renaming local vars, extracting methods, etc.
  • Multiple classpaths - IDEA has separate class paths for testing vs runtime.   In Eclipse, there is only one classpath, so you may encounter some strange results when running tests or non-test programs from within Eclipse as compared to running them from IDEA.   My advice is to not rely on running your code from the IDE.   Always know how to do things from the command line as a fallback.
  • Change lists - If you're using Git, you won't notice this.   However, if you're (still) using Subversion, change lists don't seem to be there in Eclipse.    Maybe they are, but I haven't been able to find them yet.




Thursday, June 26, 2014

Migrating from ANT and IVY to Gradle

Related to the previous post, Migrating from Maven to Gradle, here are some things I found when attempting to migrate an ANT / IVY build to Gradle.

Advantages over ANT/IVY
  • XML is not for humans - Gradle's DSL is much more readable and more concise.   No need for 'ivy.xml' and 'build.xml' and tons of 'properties files'.
  • Conventions -  Avoid re-inventing the wheel.   If you use the conventions for the Gradle plugins, this eliminates a great deal of code and makes your project look 'normal' to other people.  They can just dive right in and be productive.  "You are not special"  ;)
  • Declarative - Gradle is more declarative and eliminates a ton of boring, boilerplate code compared to ANT.
  • Plugins - Eliminate even more boilerplate code, and gain some conventions. 
    • Get dependencies.
    • Compile  the main code and the test code.  Process any resources.   Compile dependencies (multi-module).
    • Run the test suite and generate reports.
    • Jar up the main code.
  • Self install - Gradle self-installs from VCS via the gradle wrapper.
  • 'one kind of stuff' - Dependencies are declared right in the build file.
  • Daemon mode!
Getting started
  • Add build.gradle and settings.gradle to the root directory.   Can be empty files at first.
  • Gotcha #1: If you are using Subversion with the standard layout, Gradle will think that the project is named 'trunk' (or whatever the branch directory is... Subversion really sucks at branches!).

    To fix this, simply add rootProject.name='the-real-project-name' in settings.gradle.
  • Re-open the IDEA project.  IDEA will import the gradle project.
    Eclipse probably has something similar.
  • For a Java project, apply the Java plugin in build.gradle: apply plugin: 'java'
    This will automatically add the expected tasks for compiling, running tests, packaging as a jar, etc.  You don't have to write this boring stuff!
  • Custom source locations - Let's say the project has the sources in src and test_src.  This is not the standard layout for the java plugin, so we'll need to configure that in build.gradle:

    sourceSets {
        main {
            java {
                srcDir 'src'
            }
            resources {
                srcDir 'conf'
            }
        }
        test {
            java {
                srcDir 'test_src'
            }
        }
    }
    
  • Now we need to add the dependencies.   Since Gradle is based on Groovy, it's easy to make a simple converter:
    task convertIvyDeps << {
        def ivyXml = new XmlParser().parse(new File("ivy.xml"))
    
        println "dependencies {"
        ivyXml.dependencies.dependency.each {
            def scope = it.@conf?.contains("test") ? "testCompile" : "compile"
            println("\t$scope \"${it.@org}:${it.@name}:${it.@rev}\"")
        }
        println "}"
    }
    

    Just run the task and paste the output into the dependencies closure.

    We can also do something more radical: Parse the ivy.xml and populate the dependencies that way, see this post.
  •  Gocha #2: If you are using a properties file to define versions in ivy.xml, this will be a little different in Gradle.
    • Gradle supports 'extra properties' typically defined in an 'ext' closure.   These can be referenced inside double quoted strings in the dependencies closure.
    • Gradle doesn't like dots in the extra property names.   I changed them to underscore.  For example:
       
      ext {
        version_junit="4.11"
      }
      
      dependencies {
         ... blah blah blah...
         testCompile "junit:junit:${version_junit}"
      }
      
    • It's nice having everything defined in one place. :)
  • At this point, you have a basic build with compilation, testing, test reports, and all that.

Friday, June 20, 2014

Migrating from Maven to Gradle

I thought I'd share some of my experiences with migrating from Maven to Gradle for a small Java open source project.

The Strategy

First, what's the best way to do this?   The project is a fairly straightforward Java project without complex Maven pom.xml files, so maybe the best way forward is to just create a Gradle build along side the Maven one.

Some advantages over Maven


 Here are some of the advantages I found when using Gradle:
  • The 'java' plugin does almost all the work.   It defines something equivalent to the Maven lifecycle in terms of compilation, testing, and packaging.
  • Much smaller configuration.  No more verbose pom.xml files!
  • A multi-module project can be configured from the top-level build.gradle file.
  • Dependency specifications are more terse and also more readable.
  • It's much straightforward to get Gradle to use libraries that are not in the Maven repositories, e.g. in version control.   (However, I do believe that it's best to make a private repository with Artifactory or Nexus and install the libraries there, rather than keeping them in version control).
  • Dependencies between sub-modules is also very easy.
  • The whole parent/aggregator/dep-management thing in Maven is a bit clunky.   Gradle makes this much easier.  You can even do a multi-module build with a single Gradle build file if you want.

 First Attempt

Here are the steps I took.
  • Using IDEA, create a new Gradle project where the existing sources are.  Set the location of the Gradle installation.   You should see the Gradle tab on the right side panel.
  •  Create a build.gradle file and a settings.gradle file in the project root directory.
  • The basic multi-module structure can be the same as a Maven multi-module build:
    • A 'main' build.gradle file in the root directory.   Along with a settings.gradle file that has the overall settings.
    • Sub-directories for each module.
    • Each module directory has it's own build.gradle file.
    • NOTE: If the module dependencies are defined correctly, building a module will also build the other dependent modules when you are in the module sub-directory!   Major win over Maven here, IMO.
  • Apply the plugins for a Java project, set the group and version, add repositories.  In this case I have a multi-module project so I'm putting all of that in the allprojects closure:

    allprojects {
      apply plugin: 'java'
      group = 'org.jegrid'
      version = '1.0-SNAPSHOT'
      repositories {
        mavenCentral()
        maven {
          url 'http://repository.jboss.org/nexus/content/groups/public'
        }
        flatDir {
          dirs "$rootDir/lib" // If we use just 'lib', the dir will be relative.
        }
      }
    }
    

    I also have some libraries in the lib directory at the top level because they are not in the global Maven repos, or in the JBoss repo. The flatDir closure will allow Gradle to look in this directory to resolve dependencies. 
  • Add dependencies.   For a multi-module build this is done inside each project closure.   Use the 'compileJava' task to make sure they are right.
In the end, this project didn't really work with Gradle because the dependencies are too old.   So, I will need to rebuild the project from the ground up anyway.   Some of the basic libraries have undergone many significant changes since the project started, so it's time to upgrade!

Basic Gradle Multi-Module Java Project Structure

Okay, so in creating a brand new project, the canonical structure is much like a Maven project.

  • In the root directory (an 'aggregator' project) there is a main build.gradle file and a settings.gradle file.   This is roughly equivalent to the root pom.xml file.
  • In each sub-project directory (module) there is a build.gradle file.   This is roughly equivalent to the module pom.xml files.
  • The settings.gradle file has an include for each sub-project.   This is roughly equivalent to the '<modules>' section of the root pom.xml file.
  • An allprojects closure in the root build.gradle file can contain dependencies to be used for all modules.   This is similar to a 'parent pom.xml' (but much easier to read!).
One thing I wanted to do right away is to create the source directories in a brand new module.  This is pretty darn easy with Gradle.   Just add a new task that iterates through the source sets and creates the directories:

  task createSourceDirectories << {
    sourceSets.all { set -> set.allSource.srcDirs.each { 
      println "creating $it ... "
      it.mkdirs() 
      }
    }
  }

I added this in the alllprojects closure, and boom! - I have the task for all of the modules.  Neato!   I can now run this on each sub-project as needed.

Porting The Code


One I had the directory layout and basic project files I can begin moving in some of the code.    I started with the basic utility code for the project and the unit tests.   Like I mentioned, this was using a very old version of JUnit, so I needed to upgrade the tests.

Diversion One - Upgrading to JUnit 4.x

Upgrading to JUnit 4.x is actually pretty easy.   For the most part it retains backwards compatibility.   There are a few reasons you might want to upgrade the tests.
  • I prefer annotations over extending TestCase.   This is a pretty simple transform:
    1. Remove 'extends TestCase'
    2. Remove the constructor that calls super.
    3. Remove the import for TestCase
    4. Add 'import static org.junit.Assert.*'
    5. Add @Test to each test method.
  • (already mentioned) Take advantage of 'import static'! import static org.junit.Assert.*
  • Expected exceptions:
    @Test(expected=java.lang.ArrayIndexOutOfBoundsException.class)
     
  • @BeforeClass and @AfterClass annotations to replace setUp() and tearDown().

Diversion Two - Using Guice or Dagger instead of PicoContainer?

I really enjoy using DI containers.  It takes so much of the boilerplate 'factory pattern' code out of the project and makes for easy de-coupling and configuring of components.   In the previous version of the project I had used PicoContainer.   

  • Pico - Pro: Good lifecycle support.   Really small JAR file.   Con: Not as type safe.  Project seems to have stalled.
  • Guice - Pro: Not as small as Pico, but still very small.   More type safe.  Large community.  Con: Bigger jar than Pico (but not too bad... without AOP its smaller).  No real lifecycle support.
  • Dagger - Pro: Really small, with a compiler! Con: Gradle doesn't have a built in plugin for running the dagger compiler (well, as far as I can tell).
I think I'll give Dagger a try as it will cause me to learn how to make a Gradle plugin.   Even if I don't succeed, I'll learn more about how Gradle works.

See also:

Sunday, June 8, 2014

Spring for Java EE Developers

Spring has been around for a long time now, and has had a significant impact on the newer Java EE standards such as JSF, CDI, and EJB3.   In some ways, Spring could be considered a 'legacy' at this point, but since it's out there it is good to know the basics in case you find yourself working with a Spring-based system (like I have).



I'll post more as I learn, but here are my initial thoughts...



1.  Transitioning to Spring - It's not that bad

In addition to influencing the newer Java EE standards, Spring itself has been influenced by the newer standards.   I'm sure there are some people who will want to argue about which came first, etc.  This is not interesting, IMO.   Both communities benefit from the influences.
  • Annotation-based configuration - Spring no longer requires all components to be defined in a separate XML file (which is considered 'old school' at this point, although IDEs make this much easier to deal with).
    • You can actually use a combination of XML config and annotations in a manner very similar to Seam 2 and CDI.
    • You can also do "Java based" configuration like Guice or Pico.   I'm not really that keen on this approach, but it could come in handy in certain cases.
    • You still need a main configuration XML file, but that's no big deal.   In CDI you need META-INF/beans.xml and Seam you need components.xml.   The main difference is that you can configure the scanning, which could be useful.
  • Supports JSR 330 @Inject and JSR-250 lifecycle annotations - If you are already familiar with CDI and EJB3, this can make the transition easier.   The Spring-specific annotations offer some additional control (the standard annotations have limitations), but these can really help ease the transition.
  • No need for a separate POJO DI mechanism - One issue that I did experience with EJB3 / CDI is that I found I needed a POJO level underneath the EJBs to share very basic services.   I used Guice for this, as at the time Guice was very small and light.   With Spring, you can use it as your POJO DI framework too, although it's significantly slower (instantiation time) and heavier (bigger jar files) than some others.   In any case, you can use it if you have POJO Java processes that are not part of your application server cluster.   'One Kind Of Stuff' and all that.
  • JSF Integration - Spring Web Flow can be configured to integrate the Spring contexts with JSF EL, similar to Seam and CDI.
  • Spring Web Flow ~= Conversation - Having a 'sub-session' concept to allow the developer to retain state between pages is essential nowdays.   A "flow" is fairly similar to a "conversation" in Seam and CDI.  There are some significant differences in how a 'flow' is controlled, but the overall concept is the same.
  • LOTS of boilerplate-code-eliminating features! - This is something that Seam2 had a bit of, but Spring has taken this much further:
    • Spring Data - Define interfaces for DAOs, and Spring Data writes all the boilerplate JPA code.
    • Defining a DAO service that provides a RESTful JSON interface can be done with hardly any code at all.
    • Spring Roo - Generate baseline code and add components easily.   Like the 'forge' stuff in JBoss.   Not sure how useful this really is with an existing project, but it could be a quick way to get the skeleton code in there. 

2. The Bad News

NOTE: This is not an anti-Spring rant.   I'm just pointing out a few facts.
  •  Spring is big - It is no longer the case that Spring is 'lighter' than Java EE - Both systems are highly modular, and very comprehensive.   There are so many Spring add-ons now, expect to spend time wading through them.  At this point, it might as well be an application server.

    On the other hand, it is well documented and very modular, so that mitigates things.
  • Spring is not a standard, it's an implementation - This is perhaps the biggest problem I have with Spring.   It is like an alternate universe where there is only one implementation of the standard, and no independent community defining the standards.   Sure JSRs and all that have their disadvantages, but Spring does have a considerable 'vendor lock in' problem (although it is OSS, so it's partially mitigated).  Sometimes it can be good to know you can pick a different vendor without re-writing the whole thing.

    On the other hand, if you use Spring, you have a "container within the container", so the idea of porting is that you would port your inner container as well.
  • Spring AoP is more complex than EJB3 and CDI - Also a big pet peeve of mine.  It's relatively easy to make interceptors in Seam, EJB3, and CDI.   Granted, Spring AoP is much more powerful, but it's also got a lot of things that seem (to me) like they wouldn't get a lot of use.   In my experience, this kind of complexity results in two problems:
    1. Longer learning curve - Developers take more time to get familiar with the techinque.
    2. A whole new kind of spaghetti code - This often happens when a developer gets through the learning curve and then proceeds to use AoP as a "golden hammer".

    On the other hand, if you really need to do fancy stuff with AoP, (um... do you really need that?), it's there if you want it.   AoP can really be great when used wisely.
  • Lots of references to JSP in the documentation - JSP is now deprecated.   It's a huge step backward from JSF 1.2 & Facelets or JSF2.

3. Things I'm Still Figuring Out

  • Transaction / Hibernate Session management - In an older version of Spring, there were some really serious problems with Hibernate Session management and JTA.   Maybe this is no longer relevant, but I do remember looking at the Spring session management code and thinking "ugh! How did this every work?" (sorry guys).   This is probably addressed, but I do want to know if the 'extended persistence context' concept exists with Spring and/or Spring Web Flow.  This is very important to making simple, transactionally sound, high performance web apps!  
  • JSF Integration - I'm wondering just how deep this is.

Saturday, May 24, 2014

Thinking about Java 8

With all the fanfare of the impending Java 8 release, I thought it would be a good opportunity to brush up on some of the new features and think about how useful they might be at work.   Here's what I've come up with so far:

  • @FunctionalInterface - I like this as it allows me to lock down interfaces that I want to have only one method (which is what makes them functional, or function-like).   I know a co-worker or two who will really like this.
  • java.util.time - Finally!   JODA time users (like me) will find this to be very familiar looking.
  • Lambdas - I think any Groovy user will say "finally, something like groovy closures!".   This will probably come in handy, but...
    1. As with anything concise and powerful, it could be misused.  Golden hammer problems might happen (suddenly everything has to be a Lambda).
    2. The syntax is close to what Groovy does, so it might be a little confusing to those of us who switch back and forth between Groovy and Java.
    3. The combination of Lambdas and function/method reference shorthand can result in some very 'tight' code.
     
  • No more Permanent Generation -  Okay, so now classes, interned strings and static fields are in the existing 'old' generation?   Sounds good to me initially, since I'm a big fan of 'one kind of stuff'.   However, I'm not sure about how this will affect GC configurations such as the one that I use frequently at work (ParNew + CMS).
 These features reduce the gap between Java and Scala.   As good as Scala is, it's not easy to justify using it in many cases, and with Java 8, I think that set of cases got quite a bit smaller.   I'll probably learn Scala anyway, just because, but for production code I'm thinking Java 8 would be a safer bet.

Friday, May 23, 2014

Job Hunting - Networking and Recruiters

I figured I'd write about my job search here, since that's part of being a software engineering world.   Hopefully some people will benefit from some of my experiences.

  1. Keep a list of opportunities - Company name, position, status (applied, first interview, etc.) any notes about each interview.   This will come in handy when talking to your network or recruiters.   I use a Google apps spreadsheet for this.   Keep the active jobs at the top, and the 'no' list at the bottom.
  2. Use your network - Don't be afraid to reach out to your industry friends and former co-workers.   I used to feel that this was kind of... 'cheating', but that is a big mistake.   These are people that know you, that have worked with you.   You don't need to convince them of anything really.   Your friends will be happy to help you out if they can.    You would do the same for them, wouldn't you?   If they don't have anything suitable at their companies, maybe someone they know will.
  3. Go to some tech meetups in your area - In addition to maybe learning about some new things, it's a great way to meet other technical people.  Often, if a company is hiring they will encourage their engineers to go to these events and look for talent.   It might be a good idea to print up some personal business cards to hand out.
  4. Use recruiters to gain access to other opportunities - A good recruiter will have access to some opportunities that you may not know about.   They will also handle the interview scheduling, and give you more insight into the structure of the hiring company.   When you're interviewing through your network, you have to do all this yourself.  
    • Make sure the recruiter lets you know about any job before sending your resume anywhere.   Check your list to make sure you haven't already applied.
    • Remember, recruiters are getting paid by the hiring company, usually as a percentage of the yearly comp.   So, they will put much more effort into a senior level position than any junior position.
  5. Filter the opportunities, especially when going through your network - If the hiring manager requires certain technical skills that you don't have, don't just send send your resume.   If the job sounds really interesting, but your skills are not a great match, maybe a short conversation with the hiring manager is in order.   Sometimes, the hiring company wants to hire "good people" who can learn the technology specifics.   Other times, the company really wants something very specific (which IMO is a bit of a red flag), so if that's the case don't waste everyone's time by applying.
  6. Filter recruiters - If a recruiter is not showing you anything exciting, isn't efficient at scheduling interviews, or doesn't prepare you well for the interviews then move on.   No point in wasting time.  

Tuesday, April 22, 2014

Upgrading Fedora - Notes

A few notes on upgrading Fedora installations.



Fresh Install 

Probably the safest way to get a working upgrade is to back up any home directories or important configurations and go with a fresh installation.

Upgrades often leave undesirable configurations in home directories (GNOME configs, for example).  This often leads to strange desktop / display issues that can't easily by found or fixed.

You are not using OSX here.   Migrating settings and applications may or may not work.  :)

1. Create a USB Stick

On Fedora 19, these instructions didn't work for me.   Here is what I ended up doing.  Get a USB stick that doesn't have anything important on it.
  1. Download the ISO image.
  2. Insert the USB stick.
  3. Start the Disks application and select the USB drive in the left panel. 
  4. Unmount the USB disk filesystem if it is mounted. 
  5. Up at the top of the right panel, click on the gear icon and select Restore Disk Image.
  6. Select the downloaded ISO image file, and click Start Restoring.... 

2. Boot using the USB Stick, complete the installation

Shut down the machine, and re-start.   If you need to, use the BIOS to select the USB as the boot drive. 

Go through the install process.   Best to dedicate a HDD to the install, that way you can boot from that drive via BIOS boot selector if you want multiple OS's on your computer without too much hassle.   In my case, I've got a dual boot workstation, with a HDD dedicated to booting Linux.   I use the BIOS boot drive selector to boot up Fedora instead of WinDoze. 

NOTE: I've found that EZbcd doesn't play nice with UEFI boot partitions that Fedora 20 installs.    Best to just use the BIOS to select a boot disk.

 

 

 

Using FedUp

WARNING, THIS DOESN'T ALWAYS WORK.   Almost every time I've done this, there were some strange after-effects with GNome at least.

For newer versions of Fedora (newer than 17), FedUp with the network upgrade is the way to go:

$ sudo yum install fedup
$ sudo yum update fedup fedora-release
$ sudo fedup --network 20

Where 20 is the version you want to upgrade to.  Fedup will automatically reboot the system when it's done downloading everything.


The Fedora site says: "Prior to Fedora 17, the DVD/ISO/USB Drive option is recommended."

Yeah, well... what they really mean is, that FedUp will probably get you something that boots and runs some things, but you may discover later on that many settings are just plain broken.