Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Little Libraries that Save Days: Apache Commons

Posted on December 16, 2011 By Luis Fernandez

Stop writing plumbing. Grab a tiny jar and ship.

someone on a late night build

I keep running into the same quiet hero in Java projects. It is not a shiny framework. It is not a new trend on Hacker News. It is a folder of small jars that do the boring work really well. That folder is Apache Commons. While folks argue about DI and NoSQL, these little libraries quietly shave hours from our week.

We are in an odd spot right now. Java 7 just landed with new file APIs, yet most stacks still sit on Java 6. Maven Central is the pantry for everything. GitHub keeps filling up with projects by the minute. Through all that noise, Commons IO, Commons Lang, Commons Codec, and friends feel like a good pocket knife. Not flashy. Always there when you need to cut a rope.

Story one: the day a copy saved a sprint

A few weeks ago we were building a content importer. The importer chewed through thousands of files, moved them into a temp area, parsed metadata, then shipped them to S3. Everything looked fine on my laptop. On our CI box the process dragged and leaked streams. Half the failures came from code that tried to copy files with homegrown loops. I swapped that block for FileUtils.copyFile and IOUtils.closeQuietly. The leak went away. Copy was faster. We shipped that afternoon. The code got smaller and clearer. It felt like a life hack.

I wish I could say that was a one off. It was not. We keep replacing hand rolled helpers with Apache Commons calls. Every time we do it we delete code and remove bugs. That is a good trade in any sprint.

Story two: date bugs, thread bugs, and a quiet fix

Another time we had a thread pool choking on date parsing. We used SimpleDateFormat in a static field. It looked fine in unit tests. Under load it turned into a race. Costs piled up in retries and mystery timeouts. Switching to FastDateFormat from Commons Lang fixed it in one commit. It is thread safe and simple. No wrappers. No homebrew thread local. Harmony restored.

These moments add up. It is not just saved time. It is a clearer head. When a library trims noise, focus returns to the part that sets our app apart.

Deep dive one: Commons IO tricks that pay rent

File and stream code is where bugs love to hide. Commons IO gives you helpers that turn fussy code into one line. A few I keep close:

  • FileUtils.copyDirectory for safe directory moves
  • IOUtils.toString for quick stream reads with a charset
  • FilenameUtils for sane path handling without string hacks
  • Tailer for following log files without custom loops
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.input.Tailer;
import org.apache.commons.io.input.TailerListenerAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.nio.charset.Charset;

public class IoExamples {

    public static void copySiteAssets(File from, File to) throws Exception {
        // copies directories, preserves dates, creates target if needed
        FileUtils.copyDirectory(from, to);
    }

    public static String readUtf8(File file) throws Exception {
        FileInputStream in = new FileInputStream(file);
        try {
            return IOUtils.toString(in, Charset.forName("UTF-8"));
        } finally {
            IOUtils.closeQuietly(in);
        }
    }

    public static void followLog(File logFile) {
        Tailer tailer = new Tailer(logFile, new TailerListenerAdapter() {
            @Override public void handle(String line) {
                System.out.println("log: " + line);
            }
        }, 1000, true);
        new Thread(tailer).start();
    }

    public static String swapExtension(String path, String newExt) {
        return FilenameUtils.removeExtension(path) + "." + newExt;
    }
}

That is a lot of chores gone. Notice the lack of loops and the lack of try catch clutter. The code says what it does and moves on.

Deep dive two: Commons Lang patterns you can adopt today

Commons Lang is a toolbox for core types. String helpers, date helpers, object builders, validation. These helpers tighten your code and your contract with callers.

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.time.FastDateFormat;

import java.util.Date;

public class LangExamples {

    private static final FastDateFormat ISO = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ssZ");

    public static String safeTrim(String s) {
        // return empty string if null, or trimmed value
        return StringUtils.trimToEmpty(s);
    }

    public static void createUser(String email) {
        // quick guard that throws IllegalArgumentException with a clear message
        Validate.isTrue(StringUtils.contains(email, "@"), "email must contain @");
        // ... continue
    }

    public static String formatNow() {
        return ISO.format(new Date());
    }

    static class User {
        final String id;
        final String name;

        User(String id, String name) {
            this.id = Validate.notBlank(id, "id is required");
            this.name = StringUtils.defaultString(name, "unknown");
        }

        @Override public boolean equals(Object o) {
            return EqualsBuilder.reflectionEquals(this, o);
        }
        @Override public int hashCode() {
            return HashCodeBuilder.reflectionHashCode(this);
        }
        @Override public String toString() {
            return ToStringBuilder.reflectionToString(this);
        }
    }
}

The guard methods make preconditions explicit. Fewer null checks scattered around. FastDateFormat keeps the date code safe under threads, which is where many apps break.

Deep dive three: Codec and Collections for everyday tasks

Commons Codec is my go to for Base64, hex, and hashes. No need to juggle providers or write your own loops. Commons Collections gives you types you wish Java had baked in. A couple that keep showing up: MultiValuedMap behavior using MultiMap style classes and a simple LRUMap for quick caching.

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.MultiValuedMap;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
import org.apache.commons.collections4.map.LRUMap;

import java.nio.charset.Charset;

public class CodecAndCollections {

    public static String toBase64Utf8(String input) {
        byte[] bytes = input.getBytes(Charset.forName("UTF-8"));
        return Base64.encodeBase64String(bytes);
    }

    public static String sha1Hex(String input) {
        return DigestUtils.sha1Hex(input);
    }

    public static void groupByDomain(MultiValuedMap<String, String> map) {
        map.put("example.com", "alice");
        map.put("example.com", "bob");
        map.put("foo.com", "carol");
        // map.get("example.com") gives [alice, bob]
    }

    public static void quickCache() {
        LRUMap<String, String> cache = new LRUMap<>(1000);
        cache.put("k", "v");
        cache.get("k");
    }

    public static void demo() {
        MultiValuedMap<String, String> usersByDomain = new ArrayListValuedHashMap<>();
        groupByDomain(usersByDomain);
    }
}

These are focused tools. They do one thing well. When the job is a Base64 encode or a small in memory cache, reach for them and move on.

Choosing Commons with care

A few tips from projects that went well:

  • Keep the surface small. Pull the subproject you need. Not the full set.
  • Read the javadocs. Many helpers have small gotchas, like whether a copy preserves dates or not.
  • Use tests as examples. The Commons repos have solid tests. Copy from there to learn the right call.
  • Mind Java version. If you are still on Java 5 or 6, check the minimum required version for each jar.
  • Watch your classpath. Commons projects tend to be light on transitive links, which is good for sanity.

We live in a time where phones in pockets are faster than servers from a few years ago. Kindle Fire shipped last month. Siri is a thing people talk about in cabs. Through all that, the day to day of server code still needs clean file moves, clean string work, safe dates, and tested codecs.

Closing notes from a long day

There is a quiet pride in deleting a chunk of brittle code and replacing it with a clear call from Apache Commons. It is not glamorous. It does not make a splashy demo. It makes your app sturdier and your build greener. It gives you back an afternoon you can spend on the part of your product that people actually see.

If your team is new to Commons, pick one spot this week and swap in a helper. A copy here. A date format there. Watch your code shrink. Watch your bug list get lighter. These tiny libraries keep paying you back, and they do it with almost no fuss.

Small jars. Fewer bugs. More shipped work. That is a trade I will take every time.

General Software Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes