Thursday, April 18, 2013

Blobs and JDBC

A blob is a database data type for storing raw, binary data. It stands for "binary large object". In this blog post, I'm going to show you how to use this data type to insert and retrieve a photo using JDBC.

To insert the photo, start by creating an InputStream object to the photo you want to insert. For example, if the photo resides in a file, create a FileInputStream object.

File file = new File("photo.jpg");
InputStream in = new FileInputStream(file);

Then, create a PreparedStatement object for your INSERT statement. The PreparedStatement should contain a parameter for where the binary data should go, just as if you were inserting "normal" data, like a string or an integer.

Connection conn = ...
PreparedStatement stmt = conn.prepareStatement("INSERT INTO test (photo) VALUES (?)");

To set the binary data, pass the InputStream object into the setBlob() method, and then execute the statement.

stmt.setBlob(1, in);
stmt.execute();

To retrieve blob data from the database, call the getBlob() method on the ResultSet object that is returned from the SELECT statement. This will return a Blob object. Then, invoke the Blob.getBinaryStream() method to get an InputStream to the binary data.

Connection conn = ...
PreparedStatement stmt = conn.prepareStatement("SELECT photo FROM test");
ResultSet rs = stmt.executeQuery();
while (rs.next()) {
  Blob blob = rs.getBlob(1);
  InputStream in = blob.getBinaryStream();
  ...
}

Tuesday, April 16, 2013

4 Ways to Initialize a List in Java

Creating a List and populating it with a set of elements is a common programming task in Java. In this blog post, I'm going to describe four ways to do this.

1. Collections.emptyList()

This method will return a List object that is empty. This is a convenient, shorthand alternative to explicitly instantiating a new List object. However, this list is immutable, which means that you cannot add any elements to it.

List<String> list = Collections.emptyList();

2. Arrays.asList()

This method takes an array and converts it to a List object. What makes this method special is the fact that the argument to this method is a vararg. This means that you can pass as many elements into the method as you like. The syntax is very compact because all of the elements can fit on one line.

But note that, just as with Collections.emptyList(), the list that is created is immutable, so you cannot add or remove elements to/from it.

List<String> list = Arrays.asList("one", "two", "three");

3. Anonymous child class

A somewhat trickier way of creating a list is to define your list as an anonymous, child class. The elements are added to the list by calling the add() method within the class' initializer block (notice the double braces).

List<String> list = new ArrayList<String>(){{add("one"); add("two"); add("three");}}

4. JUST CALL add(), EINSTEIN!

Of course, the traditional way to create a list is to instantiate it and then call the add() method for each element. But where's the fun in that?

List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

Monday, April 15, 2013

5 Unique Features of Stackoverflow Chat

Stackoverflow, a technical question and answer site, has a web-based chat room system that allows you to talk with other programmers in real time. In this blog post, I'm going to describe five unique features of the Stackoverflow Chat system.

1. Mentions.

If you want to direct a message to a particular user, type a @ character, followed by the user's name. This will cause a "ping" sound to play in the user's browser, altering them to the fact that they were mentioned in a chat message. If the user's name has spaces in it, simply leave out the spaces.

You can also reply to specific message. To do this, hover your mouse over the message you want to reply to and click the "reply" icon on the right. Hovering your mouse over a reply will highlight the message that it was a reply to. The user who posted the message will receive a "ping".

2. Editing and deleting messages.

After sending a message, you may notice a spelling mistake or typo in your message. Stackoverflow chat allows you to edit and delete messages that are less than 2 minutes old. Hover your mouse over the message you want to edit or delete, and click the drop down arrow icon on the left.

This will open up a menu, which allows you to edit or delete your message.

3. Text formatting.

You can also format the text of your message for added emphasis. The following syntaxes are supported:

*italic*
**bold**
`code (monospaced font)`
---strikeout---

Note that, if you want to include a multi-line code sample, hold down the Shift key and then press Enter to insert a line break in your chat message (just pressing Enter will send the message). Then, you can click on the "fixed font" button to change the font of your entire message to monospace. The "fixed font" button will not appear unless your chat message has multiple lines.

4. Starred messages.

If someone posts a message that you really like, you can "star" it. Starred messages appear on the right-hand side of the window. The more stars a message has, the longer it will stay pinned to this location. To star a message, hover your mouse over the chat message you want to star, and click the "star" icon on the right.

5. Oneboxing.

If you paste URLs to particular websites into a chat messages, then the chat system will create a nicely formatted "widget" containing the content of that webpage. For example, pasting the URL to a Stackoverflow question will display various information about the question, such as the number of upvotes, the tags, and the question itself. This is called "oneboxing".

Supported websites include the Stack Exchange family of websites, Wikipedia, and Youtube.

For more information about Stackoverflow Chat, see the FAQ page.

Sunday, April 14, 2013

Javadoc and the @see tag

Javadoc, as you know, is a tool for documenting your source code in the Java language. It consists of specially-formatted comments that describe the classes, methods, and fields of your Java program. IDEs leverage Javadoc comments to help inform developers of how various APIs function (for example, hovering your mouse over a method in Eclipse will display that method's Javadoc). You can also run the "javadoc" command, which comes packaged with the JDK, to generate an HTML webpage containing the Javadoc comments of your entire code base.

Javadoc syntax defines a collection of tags. Tags allow you to describe specific aspects of your code, such as the return value of a method or the author of class. One of these tags is @see, which is like a "see also" reference. In this blog post, I'm going to describe the three ways to use @see.

1) Referring to a class or method. One way to use @see is to refer the user to another class or method within your code base. An import statement for the class you want to reference must be added to the Java code. Then, simply put the class name after the tag.

import com.example.RefClass;
/*
 * Description of this class.
 * @see RefClass
 */
public class MyClass{}

To refer to a method, put a #, followed by the method name, after the class name. If the method is overloaded, then be sure to include the parameters as well (enclosed in parenthesis) to remove any ambiguity as to which method you are referring to. Javadoc gurus will recognize this as the same syntax that's used with the @link tag.

import com.example.RefClass;
/*
 * Description of this class.
 * @see RefClass#execute(String, int)
 */
public class MyClass{}

2) Referring to a website. Another way of using @see is to refer to a website. For this, you must use the HTML <a> tag.

/*
 * Description of this class.
 * @see <a href="http://example.com">Library website</a>
 */
public class MyClass{}

3) Plain text. You can also just put plain text within the @see tag. However, it must be surrounded with double quotes in order to prevent the Javadoc parser from treating it like a class name.

/*
 * Description of this class.
 * @see "Library Documentation"
 */
public class MyClass{}

Saturday, February 9, 2013

Hard-coded XML in Unit Test code

Everyone knows that unit tests should be as self-contained as possible. Everything that is needed to run the unit test should be contained within the unit test class itself. It should rely as little as possible on other resources, such as files or database connections. This makes them easier to maintain, and makes them less susceptible to the failures of these external systems.

So what happens when your unit test needs some large block of text, like an XML document, to run? You might be tempted to put it in a separate file, but this goes against the self-containability principle described above. You might consider including them as hard-coded strings, but this isn't the best approach either. Java doesn't have a multi-line string syntax like most other languages, so doing this will strip away all the formatting that makes the XML document human-readable.

String xml = "<library><wifi>true</wifi><book><title>The Hunger Games</title><author>Suzanne Collins</author></book></library>";

By contrast, this same XML document could be defined in PHP as a multi-line string.

$xml = <<<XML
<library>
  <wifi>true</wifi>
  <book>
    <title>The Hunger Games</title>
    <author>Suzanne Collins</author>
  </book>
</library>
XML;

As you can see, the XML document in the PHP code is much more readable than the XML document in the Java code.

Despite Java not supporting multi-line strings, there is still a way that they can be mimicked. The string can be split up into multiple substrings that can be arranged however you want. These substrings are then concatenated together to form the final string.

//@formatter:off
String xml =
"<library>" +
  "<wifi>true</wifi>" +
  "<book>" +
    "<title>The Hunger Games</title>" +
    "<author>Suzanne Collins</author>" +
  "</book>" +
"</library>";
//@formatter:on

If you use the code-formatting functionality provided by an IDE, you must remember to instruct the IDE not to format this block of code. Eclipse uses a @formatter:off/on pair of comments to accomplish this (the setting for which must be manually enabled in the code formatting preferences).

Sunday, January 6, 2013

Method chaining

Jsoup is a great Java library for parsing HTML pages. Its API is elegant and easy to use. One feature I love is the way it allows a webpage to be parsed from a website URL (as opposed to providing the HTML page from a String or Reader object). It uses a technique called method chaining to build and send the HTTP request that will retrieve the webpage.

You start out by passing the URL into the Jsoup.connect(String) method. This method returns a Connection object, but you're not supposed to assign this object to a variable, as is done typically. That's not how method chaining works. Instead, you continue calling methods one after another without assigning their return values to anything. You can call as many or as few of these methods as you want. They allow you to customize the HTTP request. They all return a reference to the same Connection object (i.e. return this;), which is what allows you to call the methods in a chain-like fashion. The methods allow you to specify things like cookies and the connection timeout.

In addition to using method chaining, Jsoup.connect(String) also uses a sort of factory pattern, since its purpose is to construct an HTTP request, send it, and then parse the returned HTML page into a DOM. So, there has to be a method that terminates the chain and returns the object we want it to build. In Jsoup's case, the termination method elegantly serves an additional purpose: specifying the HTTP method (which all HTTP requests must have).

The example below parses the HTML page of google.com. It assigns some cookies to the request, specifies a connection timeout of 60 seconds, and then sends the request using the GET method.

Map<String, String> cookies = ...
Document doc = Jsoup.connect("http://www.google.com")
                    .cookies(cookies)
                    .timeout(60000)
                    .get();

Inspired by Jsoup, I've done something similar with my ez-vcard project (I will be releasing these changes in the next version of the library). To parse a vCard, you no longer have to use the relatively cumbersome VCardReader class. You can now use a method chaining API, which calls VCardReader behind the scenes. It reduces the amount of boilerplate code, making the code easier to read and understand.

//using VCardReader
File vCardFile = ...
Reader reader = new FileReader(vCardFile);
VCardReader vcr = new VCardReader(reader);
VCard vcard = vcr.readNext();
reader.close();

//using method chaining
File vCardFile = ...
VCard vcard = Ezvcard.parse(vCardFile).first();

Similarly, method chaining can be used to write a vCard as well.

//using VCardWriter
VCard vcard = ...
File vCardFile = ...
Writer writer = new FileWriter(vCardFile);
VCardWriter vcw = new VCardWriter(writer, VCardVersion.V3_0);
vcw.write(vcard);
writer.close();

//using method chaining
VCard vcard = ...
File vCardFile = ...
Ezvcard.write(vcard).version(VCardVersion.V3_0).go(vCardFile);

Method chaining can make your code a lot easier to read and understand. Have you used method chaining before? Leave a comment below.

Sunday, October 7, 2012

Deploying to Maven Central

I've been working on developing a vCard parsing library, called ez-vcard, and have decided to upload it to the Maven Central repository. This is the main code repository that all projects configured with Maven use by default. By uploading to Maven Central, developers can more easily use your library with their own projects.

This blog post documents the steps I had to take to do this. Official instructions can be found here, which is where I got most of this information. It's a fairly complex process, so make sure you take your time and don't rush yourself! Your project is going to be released to the world, so make sure you do it right!

1. Prepare the POM file

First, you have to make sure that your POM file is ready.

a. The groupId of your project must be under a domain that you control. If your project is hosted by code hosting service like Sourceforge, then you can prefix the groupId with the hosting service's domain. For example:

  • Sourceforge: net.sf.projectName
  • Google Code: com.googlecode.projectName
  • Github: com.github.projectName

b. The POM must contain the following information:

  • <modelVersion>
  • <groupId>
  • <artifactId>
  • <version>
  • <packaging>
  • <name>
  • <description>
  • <url>
  • <licenses>
  • <scm><url>
  • <scm><connection>
  • <developers>

c. It also must reference the "oss-parent" parent POM if you want to use the special Maven goals to deploy your project (explained in step 4 below).

<parent>
  <groupId>org.sonatype.oss</groupId>
  <artifactId>oss-parent</artifactId>
  <version>7</version>
</parent>

d. Also note that usage of <repository>s and <pluginRepository>s inside of your POM is strongly discouraged. All of your project's dependencies should exist inside of Maven Central.

See the POM of the ez-vcard project for an example of a well-formed POM file.

2. Submit a Sonatype JIRA ticket

You will need to create an account on the Sonatype JIRA website and then submit a JIRA ticket so that your project can be reviewed. Someone will verify that your groupId is valid and that your POM has all the required information. It takes approximately 2 business days to process your request (my ticket was approved the same day I submitted it).

For instructions on how to create a JIRA account and fill out a JIRA ticket, see the Sonatype OSS Maven Repository Usage Guide.

3. Create a public key

While you're waiting for your ticket to be approved, you can generate a public key, which will be used to sign all files that you upload to Maven Central. File signatures are required in order to deploy to Maven Central. A file's signature is stored as a plain text file with the ".asc" extension. They are used to verify whether or not the file was uploaded by the real author.

The public key can be created using a tool called GPG. Most Linux distributions come with this tool pre-installed. If you're on a Windows or Mac computer, you'll have to download it separately (see this page for instructions).

Generate the key

A key can be generated using the following command:

> gpg --gen-key

The command will ask you for the following information (the supplied default is fine for many of these steps):

  1. Key type
  2. Key size - A high key size means the key will be harder to crack, but it will take longer to generate the key and longer to verify signed files. A size of 2048 is good.
  3. Expiration date - The key can be set to never expire, but for extra security, an expiration date can be set. If an expiration date is set, you'll have to regenerate your key once it has expired.
  4. Your name and email - This information will be used to label your public key in the public key database.
  5. A comment - This can be left blank. It is an optional component of the string that is created from your name and email.
  6. Key password - This is optional, but strongly recommended. You will need to enter this every time you sign a file (i.e. every time you deploy to Central).

Afterward, the tool will start collecting data from various activities that are going on inside your computer, such as keyboard and mouse activity. It uses this random data to build a random number called a seed. This seed will be used to kick start a random number generator, which is used to generate your key. It takes a little bit of time, so be patient. Open a text editor and start typing, or just do normal work on your computer. This will speed up the seed generation process.

Distribute the key

The next step is to upload your public key to the Internet. People can then download your key and use it to verify the signatures that you've uploaded with your project files.

First, get the name of your public key. You will need this to run the command that distributes the key. For example, in the console snippet below, the name of the public key is "ED69FC1F".

> gpg --list-keys
pub   2048R/ED69FC1F 2012-09-28
uid                  John Doe <jdoe@hotmail.com>
sub   2048R/E8A6EAD8 2012-09-28

Then, distribute your public key to the Internet with this command:

> gpg --keyserver hkp://pool.sks-keyservers.net/ --send-keys ED69FC1F

There are many key servers on the Internet, but the one above is what I think Maven Central requires or recommends that you to use.

For more information, see How To Generate PGP Signatures With Maven.

4. Deploy to Central

Once your JIRA ticket from step 2 has been approved, you can upload your project to a staging repository, where it will be released to Maven Central. Remember that, once you deploy a release to Central, that version of your library is set in stone. You cannot re-release your library unless you deploy a new version!!

Prepare the project

Before you start, make sure that you do the following:

a. Add your Sonatype JIRA credentials to your Maven settings file (located at "~/.m2/settings.xml").

<settings>
  ...
  <servers>
    <server>
      <id>sonatype-nexus-snapshots</id>
      <username>your-jira-id</username>
      <password>your-jira-pwd</password>
    </server>
    <server>
      <id>sonatype-nexus-staging</id>
      <username>your-jira-id</username>
      <password>your-jira-pwd</password>
    </server>
  </servers>
  ...
</settings>

b. Add "-SNAPSHOT" to the end of the version in the POM. Even though you are deploying a release version, the project's version in the POM file must end in "-SNAPSHOT". Maven will automatically remove this when it builds and deploys your project.

c. Commit all changes to source control. The working copy of your project must have zero uncommitted changes.

Build the project

Next, run these commands to get your project ready for uploading:

> mvn release:clean
> mvn release:prepare -Dusername=SCM_USERNAME -Dpassword=SCM_PASSWORD

The "release:prepare" goal asks you for the following:

  1. The release version of your project. For example, if the version in your POM is set to "0.4.1-SNAPSHOT", the release version should be "0.4.1".
  2. The name of the SVN tag to create. The goal will automatically create an SVN tag (or equivalent object if using a different SCM) for the release, which is why you need to provide your SCM credentials in the Maven command.
  3. The new version to assign to the project after it has been deployed. For example, if you are deploying "0.4.1", you might want the new development version to be "0.4.2-SNAPSHOT".

It then performs the following operations:

  1. Does a clean build of the project.
  2. Asks for your GPG key password to sign the built files.
  3. Changes the version and SCM URLs in your POM to reflect the release version, then commits these changes to your source control system.
  4. Creates a SVN tag (or equivalent) for the release version.
  5. Changes the version and SCM URLs in your POM to reflect the new development version that was entered above, then commits these changes to your source control system.

Upload the project

The next step is to upload your project to a staging repository. The staging repository gives you one last chance to confirm that your project is in good shape and ready to be released to the world. It also performs automated checks on your project to make sure it meets all the requirements.

> mvn release:perform

This command will:

  1. Checkout the SVN tag (or equivalent) that was created with the "release:prepare" goal.
  2. Build the checked-out files.
  3. Ask for your GPG key password to sign the built files.
  4. Upload everything to a staging repository (not Maven Central yet).

Release

Now that your project is in the staging repository, you can release it to the world!

  1. Open the Nexus UI by visiting https://oss.sonatype.org/. Login with the JIRA credentials you created in step 2.
  2. Click on "Staging Repositories" in the menu on the left.
  3. Find the staging repository for your project. Select it, then click the "Close" button. You will be asked to enter a comment describing your action. You can enter something like "Release of version 0.4.1". Closing the repository will perform some automated checks on your project. It makes sure that all files are signed, that your POM has all the required information, and that your project has source code and Javadoc JARs.
  4. If there is a problem with your project, you can click "Drop" to delete the staging repository so you can correct the mistakes, re-build, and re-stage your project.
  5. Once you've confirmed that your project is in good shape, click "Release". If the "Release" button is disabled, it means it is still performing some automated checks on your project. Wait a few seconds, then click the "Refresh" button. The "Release" should become enabled (if it is not, wait a few more seconds, then click "Refresh" again). After clicking "Release", you'll be asked again to enter a comment.
  6. Since this is the first time you are deploying your project to Central, your project must be manually reviewed to make sure everything is OK. Add a comment to the JIRA ticket that you created in step 2, saying that you have released the project. If everything is OK, then the Maven folks will configure your project to sync with Maven Central. It will appear there within 2 hours. All subsequent versions you release will be automatically synced with Central and this last step will not be necessary. It will take approximately 4 hours to appear on search.maven.org.

Congratulations! Your project is now part of the Maven community!

For more information, see the Sonatype OSS Maven Repository Usage Guide.