User Tools

Site Tools


middleware:java

Java

Class Equality

In most cases, Class#isInstance() and Class#isAssignableFrom() behave similarly in that both consider equality by considering assignment compatibility, i.e. the argument (or an instance of its class) can be assigned to this class. With Java 1.5 and autoboxing of primitives, there is an important difference between the two that can be demonstrated with the following trivial program:

public class AutoboxingEqualsTest {
  public static void main(final String[] args) {
    final Integer integer = new Integer(3);
    final int i = 3;
    System.out.println(
      "Integer.getClass().isInstance(int) == " +
        integer.getClass().isInstance(i));
    System.out.println(
      "Integer.getClass().isAssignableFrom(Integer.TYPE) == " +
        integer.getClass().isInstance(Integer.TYPE));
  }
}

The code above outputs the following when executed:

Integer.getClass().isInstance(int) == true
Integer.getClass().isAssignableFrom(Integer.TYPE) == false

Thus Class#isInstance() treats a primitive and its wrapper as equal, while isAssignableFrom() does not.

Java Remote Debugging

Several of my colleagues have an IDE aversion, preferring to develop with VIM and troubleshooting with logging statements. This sort of development strategy is fine, and even preferable, for the sorts of JEE applications we develop that need a container to provide services that are unavailable or not conveniently available in a development environment.

One of the primary benefits of an IDE is being able to run code in a debugger to see a wealth of state information. I routinely track down minor bugs during unit testing by running the tests from an IDE. There are many test scenarios, however, that require a test harness of sufficient complexity that it is usually bootstrapped via some external build tool like Ant. For those situations, and for the IDE-averse, the JVM remote debugging facilities may be used to perform the usual IDE debugging session. The following sketches out the steps to accomplish this. We will assume the Eclipse IDE for this discussion, but the instructions are simple enough that they should be easily adapted to your favorite IDE.

  1. Create an Eclipse Java project from your source. (If you need instructions on how to do this, Google FTW!)
  2. Open the Eclipse debug dialog and create a new “Remote Java Application” debug configuration. The only thing that needs customization is the project and possibly the port number, but the default 8000 is convenient. It is also helpful to select the “Allow termination of remote VM” option.
  3. Open a terminal and cd into the root of your source tree. We'll assume there is a test ant target that run JUnit unit tests. Make sure you have the fork=“yes” and clonevm=“true” attributes set on your junit task:
    <junit printsummary="yes" fork="yes" haltonfailure="no" clonevm="true">
      <classpath>
        <path refid="compile.classpath" />
        <pathelement location="${work.classes.dir}" />
        <pathelement location="${work.test-classes.dir}" />
      </classpath>
      <formatter type="plain" usefile="false" />
      <batchtest fork="perbatch">
        <fileset dir="${test-src.dir}">
          <include name="**/*Test.java" />
        </fileset>
      </batchtest>
    </junit>
  4. Execute the following ant command. You will see a status message indicating that the JVM is paused awaiting connection of the external debugger, in this case Eclipse.
    ANT_OPTS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y" ant test
  5. Launch the Eclipse remote debug configuration created in the second step and debug as usual.

Apache Maven

Mavenized builds can start a remote socket listener as follows:

MAVEN_OPTS="-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=y" mvn clean test

Encrypted Passwords

The 2.0 version of the Middleware vt-crypt Java library has a command line interface that natively supports base-64 and hex encoding of output ciphertext. A command like the following may be used to generate base-64 encoded ciphertext passwords used in build files:

echo -n "PassPhraseHere" | enc -encrypt -cipher AES \
    -key path/to/aes.key \
    -iv 3858f62230ac3c915f300c664312c63f \
    -encoding base64

slf4j Notes

The slf4j logging library is rapidly replacing the venerable log4j as the de-facto logging library used in Java applications. Although slf4j is often compared to log4j, slf4j is a logging facade like Jakarta Commons Logging instead of a logging engine in itself like log4j. Some notable features of slf4j:

  • Compile-time binding to a logging engine (versus runtime binding used by Commons Logging)
  • Performance enhancements
  • Bridges to all other common logging frameworks
    • Commons logging
    • JDK logging
    • log4j
  • Support for newer logging engines such as logback

The static binding is perhaps the most notable feature of slf4j from the perspective of an enterprise application where classloaders and isolation are primary concerns.

Since many libraries have an investment in other logging frameworks, particular Commons Logging, the use of the logging bridges is very common in a large project. It is _very_ important to ensure that if a bridge is being used, that the corresponding logging framework or engine library is not accessible in the same classloader. For example, a Web application that depends on a library that uses log4j natively would require the log4j-over-slf4j bridge; in order to migrate to slf4j, the log4j.jar should be replaced by log4j-over-slf4j.jar and the other slf4j jars should be added as well as a logging engine such as logback.jar.

middleware/java.txt · Last modified: 2015/06/01 12:02 (external edit)