Showing posts with label maven. Show all posts
Showing posts with label maven. Show all posts

Friday, August 11, 2017

How to write clean Java

I cannot tell you how to write good Java, but I can help you write clean Java. As usual, automation is key. It's all about the tooling.

The best thing about good tooling is that they work together: each covers a different area, does not impeded another tool, and fixing one complaint a tool reveals often fixes complaints from other tools.

This advice applies to any programming language, not just Java. Java, having the most mature ecosystem, is instructive.

The tools

Use good source control
Git is your best choice. Use either trunk-based development with feature toggles (feature flags), or gitflow patterns, depending on your needs and organization. Require full builds and testing before pushing to a shared repository; hooks can help together with your build tool.
Use good build automation
Maven or Gradle are your best choices; either is excellent. Teach the tool to be strict and fail builds if anything is not just right. Treat your build configuration as code, part of the same repository and held to the same hygiene standards. Keep your local build fast.
Use a good editor
IntelliJ is the best choice. Use inspections, intentions, and reformatting obsessively: code diffs should only show real changes, not whitespace or formatting. Use plugins to ease integrating IntelliJ with other tooling.
Keep your style consistent
Checkstyle is your best choice; other choices are needed for non-Java JVM languages. Fail your build if checkstyle complains. Keep your IntelliJ formatting and Checkstyle rules consistent. Generally, choose either Sun or Google coding standards, and be leary of deviating from them; if unsure, pick Sun.
Fully test your code
JaCoCo works well. Fail your build if coverage drops below a threshhold; rachet up the threshhold as coverage improves. Start low and aim for a 95%+ threshhold. Follow the Test Pyramid; save your end-to-end tests for CI, or run locally only once before pushing commits.
Be zealous in looking for problems
FindBugs, PMD, or Error Prone are your best choices (pick one); other choices may work better for non-Java JVM languages. Fail your build if your choice complains. Be judicious in disabling complaints (for example, FindBugs "experimental" checks, should likely be disabled).
Use code generation
Lombok is your first choice. Add others as needed (or build domain-specific code generators). Generated code does not need test coverage, style checks, or bug detection if the generator is clean and well-tested: trust it.

Update

Dan Wallach reminded me of Error Prone, added above.

Saturday, April 29, 2017

Maven color logging on Cygwin

WORKAROUND: Thanks to comment by Zart Colwing, there is a workaround. Add -Djansi.passthrough=true to MAVEN_OPTS. It is not enough to add the flag to the command line; it needs to be seen by JANSI before maven begins parsing the command line. See No color for maven on Cygwin to track the issue.

Post

I'm quite happy Maven 3.5.0 has added color logging!

With earlier versions of maven, I used Jean-Christophe Guy's excellent maven-color extension. On Windows that involved some manual hacking of my maven installation, but on Mac, it was trivial with homebrew.

So now I'm getting color output from maven out of the box. Except when I don't.

You see, this new feature relies on the good JAnsi library. And JAnsi presently has an issue with color on Cygwin. When I'm at home, Cygwin is my mainstay, used on my gaming-cum-programming rig, so this is significant to me. What is the issue? No color—JAnsi detects I'm on Windows, and uses the native Windows console color handling, which doesn't work in Mintty or Xterm. Those use standard ANSI escape sequences, etc. rather than an OS-specific library.

Digging through the source for JAnsi, I find the trouble spot:

private static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win");

Aha! The special Windows-handling code kicks in when the os.name system property contains "win" (in any case). Using the jps and jinfo tools that come with the JDK, I double-checked against a long-running maven build (16848 just was the PID used by the JVM for this maven build; use jps to list all current PIDs):

$ jinfo -sysprops 16848 | grep os.name
os.name = Windows 10

Some experimenting found a way to work around that:

MAVEN_OPTS=-Dos.name=Cygwin mvn clean

(You need to use MAVEN_OPTS rather than passing -Dos.name=Cygwin to maven; once maven starts the value is immutable.)

Color is back. It turns out, any value for os.name will work (for example, "Bob") as long as it doesn't contain "win". I picked "Cygwin" for explicitness.

UPDATE: I have to rethink this. Sure I get color now, but at the expense of maven test failing as maven no longer believes I'm on Windows, so is unhappy at the lack of a /bin/sh and general UNIX filesystem. One step forward, two steps back.

Tuesday, April 04, 2017

Maven logging and the command line

I usually set up my Maven-build projects to be as quiet as possible. My preference is "Silence is Golden": if the command says nothing on the command line, it worked; if it failed, it prints to STDERR.

However, sometimes I want to see some output while I'm tracking down a problem. How best to reconcile these?

Maven 3.3.1 (maybe earlier) introduced the .mvn directory for your project root (note leading DOT). In here you can keep a jvm.config file which has the flags to the java command used when running mvn. Here's my usual jvm.config:

-Dorg.slf4j.simpleLogger.defaultLogLevel=WARN
-Dorg.slf4j.simpleLogger.log.Sisu=WARN

This quiets maven down quite a bit, using the properties to control Maven's more recent logger, SLF4J. And I normally commit that into my project code repository.

And for those times I'd like more output? I could edit the file, but I don't trust myself enough not to accidentally commit those temporary changes. So I use the command line:

$ MAVEN_OPTS='-Dorg.slf4j.simpleLogger.defaultLogLevel=INFO' mvn

Ultimately mvn reads .mvn/jvm.config, putting the contents into the variable MAVEN_OPTS, and uses MAVEN_OPTS in the invocation of java, and you can override the variable yourself on the command line.

Monday, February 29, 2016

Maven testing module

My usual practice is to put test dependencies in my Maven parent POM when working on a multi-module project. And I usually have a "testing" module as well for shared test resources such as a logback-test.xml to quiet down test output.

The test dependencies look like clutter in my parent POM, and they are, or so I recently realized.

As all my non-test modules use the "testing" module as a test dependency, I clean this up by moving my test dependencies out of the parent POM and into the "testing" module alongside the common resources. So my layout looks like:

Parent POM
Common properties such as dependency versions, dependencies management marks the "testing" module as "test" scope.
Testing POM
Test dependencies not marked as "test" scope—consumers of this module will mark it as "test", and its transitive dependencies will automatically be "test" as well.
Non-test POMs
Use the "testing" module as a dependency—specified in the parent POM dependencies management—, no test dependencies or resources inherited from parent POM.

Examples:

Sunday, February 21, 2016

Modern maven

I've pushed my first release of Modern-J, a maven archetype (project starter), to github. Mostly this is for myself, to have a decent maven archetype for starting spikes and projects.

One thing I learned about maven is dealing with version mismatch in dependencies. The technique is not to modify <dependency> blocks with exclusions but to add a <dependencyManagement> block:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

(My POM sets "junit.version" to 4.12.)

This resolves the dependency mismatch between current JUnit (4.12) and the JUnit for System-Rules (4.11), a wonderful JUnit @Rule I hope to see eventually bundled with JUnit itself.

UPDATE: Hat tip to Qulice who beat me there first, though I'm not as strict.

Sunday, October 18, 2015

Downloading sources and javadocs automatically

Thanks to Ted Wise, I taught my "modern java" build to automatically download sources and javadocs. Using maven:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>${maven-dependency-plugin.version}</version>
    <executions>
        <execution>
            <id>download-sources</id>
            <phase>generate-sources</phase>
            <goals>
                <goal>sources</goal>
            </goals>
        </execution>
        <execution>
            <id>download-javadocs</id>
            <phase>generate-sources</phase>
            <configuration>
                <classifier>javadoc</classifier>
            </configuration>
            <goals>
                <goal>resolve</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Friday, October 16, 2015

Struggling with Travis CI and Maven 3.3

I struggled with fixing Travis CI for my "labs" code. The main problem is lack of support for Maven 3.3; my POM enforcer requires it. Eventually I got something working with help from the Internet, though I'm not happy with it. It manually downloads and uses maven 3.3:

sudo: false
language: java
jdk:
  - oraclejdk8
# TODO: Gross until Travis support setting maven version or upgrades to 3.3
before_install:
  - wget http://apache.claz.org/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz
  - tar zxvf apache-maven-3.3.3-bin.tar.gz
  - chmod +x apache-maven-3.3.3/bin/mvn
  - export M2_HOME=$PWD/apache-maven-3.3.3
  - export PATH=$PWD/apache-maven-3.3.3/bin:${PATH}
  - hash -r
before_script:
  - export M2_HOME=$PWD/apache-maven-3.3.3
  - export PATH=$PWD/apache-maven-3.3.3/bin:${PATH}
  - hash -r
script: mvn verify -Dgpg.skip=true

Bonus

On another project using Travis CI I ran afoul of the 10,000 line limit for displaying build output in the web UI. Workaround, add this to the build_install section:

  - echo 'MAVEN_OPTS="-Dorg.slf4j.simpleLogger.defaultLogLevel=warn"' >~/.mavenrc

If you're using maven 3.3 or better, Karl Heinz Marbaise has a better approach with .mvn/jvm.config.

Tuesday, October 06, 2015

Automating dependency versions in Maven

Reading the most excellent Modern Java series of posts, I realized I could automate a command line step I always did manually—updating dependency versions:

$ mvn versions:update-properties

I can automate that! The simplest possible POM demonstrating:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>example-group</groupId>
    <artifactId>example-artifact</artifactId>
    <version>0-SNAPSHOT</version>

    <properties>
        <example-dependency.version>1</example-dependency.version>
        <generateBackupPoms>false</generateBackupPoms>
        <versions-maven-plugin.version>2.2</versions-maven-plugin.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>example-group</groupId>
            <artifactId>example-dependency</artifactId>
            <version>${example-dependency.version}</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
                <version>${versions-maven-plugin.version}</version>
                <executions>
                    <execution>
                        <id>update-dependencies</id>
                        <phase>validate</phase>
                        <goals>
                            <goal>update-properties</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

My hypothetical maven build says:

$ mvn clean
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building example-artifact 0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ example-artifact ---
[INFO]
[INFO] --- versions-maven-plugin:2.2:update-properties (update-dependencies) @ example-artifact ---
[INFO] Property ${example-dependency.version}: Leaving unchanged as 1.2.3
[INFO] Property ${versions-maven-plugin.version}: Leaving unchanged as 2.2

The key is using <phase>validate</phase> in the plugin execution. The first lifecycle phase for maven is "validate". Setting the property "generateBackupPoms" to "false" prevents pom.xml.versionsBackup files from littering the project. You are using source control, aren't you?

Update

This approach is best during development, especially for greenfield projects. I would not recommend it for stable or legacy projects where dependency versions need to be kept constant.

Friday, October 18, 2013

Signing maven releases with gpg while keeping your passphrase secure

On the road towards putting sample code into Maven Central I stumbled at GPG signatures of my artifacts. The problem was how to handle my passphrase.

The recommended solutions (one source of many) all had shortcomings:

  • Prompting for your passphrase is often unuseful and is broken when running maven in Cygwin.
  • Putting your passphrase on the command-line is visible to ps and is saved in history.
  • Putting your passphrase into {{settings.xml}} leaves it on disk.
  • Putting your passphrase on removable media and linking to it in {{settings.xml}} is awkward.
  • Using a gpg agent would be best, but I did get everything hooked up right; I should investigate further.
  • I will not even entertain removing the passphrase from my secrets just to satisfy maven.

A little think and some trial and error led me to:

  1. In pom.xml enable maven-pgp-plugin and configure maven-release-plugin:
    <plugin>
        <artifactId>maven-release-plugin</artifactId>
        <configuration>
            <arguments>-Dgpg.passphrase=${gpg.passphrase}</arguments>
        </configuration>
    </plugin>
  2. In settings.xml add a profile:
    <profile>
        <id>gpg-sign</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <properties>
            <gpg.passphrase>${env.GPG_PASSPHRASE}</gpg.passphrase>
        </properties>
    </profile>
  3. Write a small helper shell script:
    #!/usr/bin/bash
    
    read -er -p 'Passphrase: ' gpg_passphrase
    echo # Get back newline
    GPG_PASSPHRASE="$gpg_passphrase" exec "$@"

The key observation is that environment variables are private to the process, in memory and transient. I invoke thus:

$ ./rls mvn clean verify
Passphrase:
[INFO] Scanning for projects...

Friday, August 30, 2013

Overwhelmed: git flow, github, maven and central

I decided to publish code to Maven central providing extended version of this blog's sample code. And I have become fascinated with gitflow. So I am stirring the pot, mixing git, github, maven and the central repo. Wish me luck. I'll post a "howto" when it works well enough.

Monday, September 26, 2011

Maven, the ideal vs. the reality

Rob Williams describes his maven woes. His solution is nexus, which is great software. But why is this Rube Goldberg set up required? Again, maven.

Thursday, July 14, 2011

A reminder why make is a beast

At work today was a vivid reminder why make is a beast.
I'm integrating protobuf into a custom build system based on GNU make, call it yamake ("yet another make") and a proprietary IDL-like language, call it SDL ("sort-of definition language"). SDL is firmly rooted in the culture and systems, so it is non-negotiable. Over the course of the past few days, learned the steps:
  1. Write a backend for the Python compiler script which translates SDL to your target language, in my case protobuf.
  2. Hand off protobuf backend to guru colleague who munges it to better match the overall systems, and patches it into yamake.
  3. Work on makefile to actually build usable jar of compiled protobuf for Java.
  4. Watch colleague redo munging to something more permanent, less hacktastic.
  5. Rework on makefile to actually build usable jar of compiled protobuf for Java.
  6. Roll fake maven local repo holding new jar, of course yamake knows nothing about deploying jars.
  7. Build new CORBA IDL jar for Java including new interfaces to access protobuf in other systems.
All this, and finally I can actually do useful work. Tomorrow.
But this is not the point of my post.
Yamake is a wrapper around venerable GNU make, so I am editing makefiles. Ultimately I have this dependency chain: SDL to protobuf to Java to classes to jar. But watch:
$ sdlc -t protobuf foobar.sdl -o proto/foobar.proto
$ protoc --java_out=java proto/foobar.proto
$ javac -sourcepath java java/my/package/FoobarProtos.java
$ jar cf foobar.jar -C java my/package/FoobarProtos*.class
It's actually more Rube-Goldbergesque than this, as the C++ versions of the protobuf play games with namespaces requiring various flags at various stages along with directory changes. So I made Java keep up. You come up with dependency rules that cope with option java_package = "something.random" and option java_outer_classname="SomethingProtos" and mismatched output directories!
I opted for using helper shell scripts for parsing protobuf for proper Java packages with class names and generating dependency makefiles to include in my actual makefile.
Maven, remind me to quit poking on you for your ugly XML and ridiculously noisy output. I forgot all the love you give me.

Friday, September 10, 2010

Getting maven dependency sources and javadocs

I found Ted Wise posting on the problem I tackled today: how to download sources and javadocs from command-line maven:

$ mvn dependency:sources
$ mvn dependency:resolve -Dclassifier=javadocs

Unsure why the discrepancy.

Thursday, August 26, 2010

Guice moving to Maven

It's not new news, but it was new to me: Maven is switching to Guice to wire itself and plugins. From Sonatype:

  1. From Plexus to Guice (#1): Why Guice?
  2. From Plexus to Guice (#2): The Guice/Plexus Bridge and Custom Bean Injection
  3. From Plexus to Guice (#3): Creating a Guice Bean Extension Layer

The plugin framework is named spice inject and glancing through it's straight-forward glue between Guice and OSGi within a Maven object domain.

It looks very clean. Nice.

Thursday, January 07, 2010

IntelliJ and Scala

Thomas Jung writes about using IntelliJ and Scala and is very enthusiastic, as he should be: IntelliJ IDEA remains the best IDE.

I've long been pessimistic of IDEA retaining this position in the face of thousands of Eclipse code monkeys eventually typing the works of Knuth, but JetBrains has admirably kept up.

The struggle between the cathedral and the bazaar continues.

UPDATE: When it rains, it pours.

Thursday, July 31, 2008

Progress in Functional Java

I have been happy lately to see the progress in Functional Java. A project truly arrives when it becomes the inspiration for other clever ideas. Witness Lazy Error Handling in Java, Part 1: The Thrower Functor.

Every few days comes another fun bit of functional programming creeping its way in to my workaday language, Java. Current wish list item: the fj team deploys to a public Maven repository so I can just say:

<dependency>
    <groupId>fj</groupId>
    <artifactId>functionaljava</artifactId>
    <version>2.8</version>
</dependency>

UPDATE: This just gets more interesting: Lazy Error Handling in Java, Part 2: Thrower is a Monad and Lazy Error Handling in Java, Part 3: Throwing Away Throws.

Tuesday, August 21, 2007

Cygwin BASH wrapper for Maven deploy:deploy-file

I frequently use Maven's deploy:deploy-file mojo for building project-local repositories.

Many interesting 3rd-party Java libraries are not (yet) available from public Maven repositories (the otherwise excellent dev.java.net projects are particularly weak in this respect), but I want to use them in my project POM. What to do?

I store them with my project. This is not an ideal solution, but it is practical.

To help me deploying jars, sources and javadocs I wrote a simple BASH wrapper script for Cygwin (to run under Linux/UNIX requires a trivial change). Here is typical use:

$ mvn-file-deploy ~/IdeaProjects/Scratch/lib cool-library-1.0.4.jar org.cool.library:cool-library:1.0.4
$ mvn-file-deploy -S ~/IdeaProjects/Scratch/lib cool-library-1.0.4-sources.jar org.cool.library:cool-library:1.0.4
$ mvn-file-deploy -J ~/IdeaProjects/Scratch/lib cool-library-1.0.4-javadocs.jar org.cool.library:cool-library:1.0.4

And the script itself:

#!/bin/bash

function help()
{
    cat <<'EOH' | fmt
Usage: mvn-file-deploy [options] REPO_PATH FILE_PATH DESCRIPTOR [CLASSIFIER]

Use mvn-file-deploy as a helper for 'mvn deploy:deploy-file' when using Cygwin.

EOH
    cat <<'EOH'
Options:
  -h, --help          Print this help message
      --version       Print program version
  -S, --sources       Deploy sources
  -J, --javadocs      Deploy javadocs
  -q, --quiet         Do not print maven command
EOH
    cat <<'EOH' | fmt

Other options are passed to Maven.  (BROKEN)

Examples:

The most common use is to run it like this:

    $ mvn-file-deploy C:/my/project/lib C:/some/interesting.jar groupId:artifactId:version

Or if you use a classifier (e.g., jdk5):

But sometimes like this.

    $ mvn-file-deploy C:/my/project/lib C:/some/interesting.jar groupId:artifactId:version classifier

Report bugs to <binkley@alumni.rice.edu>.
EOH
}

function version()
{
    cat <<'EOV' | fmt
mvn-file-deploy 1.0
Copyright (C) 2007 JPMorganChase, Inc.  All rights reserved.
EOV
}

function fatal()
{
    echo "$0: $*" >&2
    exit 2
}

function usage() 
{
    cat <<'EOU' | fmt >&2
usage: mvn-file-deploy [options] REPO_PATH FILE_PATH DESCRIPTOR [CLASSIFIER]
EOU
}

eval set -- "$(getopt -o hJSq --long help,javadocs,sources,quiet,version -n "$0" -- "$@")"

declare -a maven_opts
declare -a args

for opt
do
    shift
    case "$opt" in
        -h|--help ) help ; exit 0 ;;
        -J|--javadocs ) classifier=-Dclassifier=javadocs ;;
        -S|--sources ) classifier=-Dclassifier=sources ;;
        --version ) version ; exit 0 ;;
        -q|--quiet ) quiet=t ; maven_opts=("${maven_opts[@]}" "$opt") ;;
        -- ) break ;;
        -* ) maven_opts=("${maven_opts[@]}" "$opt") ;;
    esac
done

case $# in
    3 ) repo_path="$1"
        file_path="$2"
        descriptor="$3" ;;
    4 ) repo_path="$1"
        file_path="$2"
        descriptor="$3"
        classifier=-Dclassifier="$4" ;;
    * ) usage ; exit 2 ;;
esac

(cd "$repo_path" 2>/dev/null) || \
    fatal "No such repository path: $repo_path"

repo_url="file://$(cygpath -am "$repo_path")"
file_path="$(cygpath -am "$file_path")"

[[ -r "$file_path" ]] || \
    fatal "No such artifact: $file_path"

triplet=($(echo $descriptor | tr : ' '))

(( 3 == ${#triplet[*]} )) || \
    fatal "Descriptor not groupId:artifactId:version format: $descriptor"

packaging=-Dpackaging="${file_path##*.}"

[[ -n "$quiet" ]] ||
    echo mvn "${maven_opts[@]}" deploy:deploy-file -Durl="$repo_url" \
        -DrepositoryId=project -Dfile="$file_path" -DgroupId=${triplet[0]} \
        -DartifactId=${triplet[1]} -Dversion=${triplet[2]} \
        $packaging $classifier
exec mvn "${maven_opts[@]}" deploy:deploy-file -Durl="$repo_url" \
    -DrepositoryId=project -Dfile="$file_path" -DgroupId=${triplet[0]} \
    -DartifactId=${triplet[1]} -Dversion=${triplet[2]} \
    $packaging $classifier

Saturday, March 10, 2007

Storing jars in a Maven project

One of the sweetest things about Maven is that depedencies are stored external to your sources: if you depend on Apache Commons Lang 2.3, for example, then you can stick this in the dependencies section of your pom.xml and stop worrying:

<depedency>
    <groupId>commons-lang</groupId>
    <artifactId>commons-lang</artifactId>
    <version>2.3</version>
</dependency>

But what do you do when your dependency is not available in a public Maven repository? For example, the library is too new to be widely available, or is proprietary like the Oracle JDBC driver?

One tack is to establish an internal repository and refer to that in your pom.xml. But sometimes that is not practical, perhaps because of corporate network use restrictions, or for very small projects.

Before Maven, common practice was to stash dependencies into a directory named lib/ or similar underneath the root of your project sources. When no other solution presents itself, you can follow that practice but keep using Maven.

In your pom.xml, add this top-level section:

<repositories>
    <repository>
        <id>project</id>
        <name>Project Maven Repository</name>
        <layout>default</layout>
        <url>file:///./lib</url>
    </repository>
</repositories>

This establishes the lib/ directory underneath your project as a Maven repository relative to your project root. Now you can stash dependencies there, store them with the rest of your project resources, but keep using Maven.

A little bit more

Often I have to re-lookup the documentation on deploy:deploy-file so that I can put a dependency in an internal repository or in the project repository as described above. Here is a magic incantation example:

$ cd /PATH-TO-guice-1.0-DOWNLOAD
# Checkout the SVN 1.0 tag sources to src/
# Note -- need to use the -Dversion=1.0 switch
# because pom says 1.0-RC2 in spite of tag.  Then:
$ mvn deploy:deploy-file \
    -Durl=file://C:/FULL-PROJECT-PATH/lib \
    -DrepositoryId=project -Dfile=guice-1.0.jar \
    -DpomFile=src/pom.xml -Dversion=1.0
# Pack up the javadocs and sources into jars, then:
$ mvn deploy:deploy-file \
    -Durl=file://C:/FULL-PROJECT-PATH/lib \
    -DrepositoryId=project \
    -Dfile=guice-1.0-javadocs.jar \
    -DpomFile=src/pom.xml -Dversion=1.0 \
    -Dclassifier=javadocs
$ mvn deploy:deploy-file \
    -Durl=file://C:/FULL-PROJECT-PATH/lib \
    -DrepositoryId=project \
    -Dfile=guice-1.0-sources.jar \
    -DpomFile=src/pom.xml -Dversion=1.0 \
    -Dclassifier=sources

I now have the splediferous Guice 1.0 dependency in my project repository, and can use it in my pom.xml with:

<depedency>
    <groupId>com.google.inject</groupId>
    <artifactId>guice</artifactId>
    <version>1.0</version>
</dependency>