Archive

Archive for April, 2013

Quick decompile of Java code

April 29, 2013 2 comments

If you need to quickly decompile a java .class file and you only have access to a machine with the JDK installed on it (like production servers) – you can use a tool which is built-in with the JDK.

It is called javap and it can disassemble any .class file. All you need to do is run it from the directory where all of your the .class files exist (the “root”).
It will also work if the class can be found within the CLASSPATH (i.e. the environment variable CLASSPATH) and it can be given a specific classpath via a CLI argument. It can also find the .class file within a JAR.

javap <FQCN> Usage Gets the list of all the public members (variables + methods).
Only gives you method declerations.
Example javap java.lang.String
javap -private <FQCN> Usage Gets the list of all the members (variables + methods).
Only gives you method declerations.
Example javap -private java.lang.String
javap -c <FQCN> Usage Same as javap <FQCN>, but also disassembles the method body.
This does not “decompile” – but you can understand what will happen in simple methods.
Example javap -c java.lang.String
javap -c -private <FQCN> Usage Same as above but does it for all private members as well.
Example javap -c -private java.lang.String

FQCN: Fully Qualified Class Name.

How does it look? Take for example this piece of code:

package com.ron;

import java.lang.*;

public class JavapSample
{
        private String someMember;

        public JavapSample(int someArgument)
        {
                someMember = String.valueOf(someArgument);
        }

        public void doSomething()
        {
                System.out.println(someMember);
        }

        private void doSomethingSecret()
        {
                System.out.println("Secret ...");
        }
}

Here is the output:

public class com.ron.JavapSample extends java.lang.Object{
    public com.ron.JavapSample(int);
    public void doSomething();
}
public class com.ron.JavapSample extends java.lang.Object{
    private java.lang.String someMember;
    public com.ron.JavapSample(int);
    public void doSomething();
    private void doSomethingSecret();
}
public class com.ron.JavapSample extends java.lang.Object{
private java.lang.String someMember;

public com.ron.JavapSample(int);
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   iload_1
   6:   invokestatic    #2; //Method java/lang/String.valueOf:(I)Ljava/lang/String;
   9:   putfield        #3; //Field someMember:Ljava/lang/String;
   12:  return

public void doSomething();
  Code:
   0:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   aload_0
   4:   getfield        #3; //Field someMember:Ljava/lang/String;
   7:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   10:  return

private void doSomethingSecret();
  Code:
   0:   getstatic       #4; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #6; //String Secret ...
   5:   invokevirtual   #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return
}

Where/When to use it – I use it when I need to ensure a certain fix is available within a JAR on a QA/Prod environment. It is not intrusive – and it is rather easy to understand if the fix is there or not.

Note for Java7 users: In java 7 it looks like javap can receive a .class file as an argument instead of the FQCN.

Categories: Java, Tools Tags: , ,

Where did that Class come from?

April 21, 2013 Leave a comment

Too many times I watched the logs trying to understand why I got the NoSuchMethodError. I sometimes get it with other derivatives of IncompatibleClassChangeError (AbstractMethodError, IllegalAccessError, InstantiationError, NoSuchFieldError) but NoSuchMethodError is the most common one.

The reason for this error is simple – the class you want to use is not the one being loaded at run time. This can be another version of the third party that finds its way to the classpath, or some old copy of your class. The problem is usually pin-pointing where it got from.

For that I have a simple solution – which unfortunately requires some code modification.
All you need to do is add these lines to your code (modify slightly) and you will get the result:

String className = classYouWantToFind.getName();
String classFileRelativePath = className.replace('.', '/') +  ".class";
java.net.URL classFileUrl = this.getClass().getClassLoader().getResource(classFileRelativePath);
System.out.println(className + " comes from [" + classFileUrl.toString() + "]");

This code asks the ClassLoader of the currently running object to find the .class representing the class you are looking for. Since the class loader searches for resources in the same order as it does for classes – it should find the correct one.

You can see a live example of this code on IDE One.

Note: You can always get this result by adding the -verbose:class VM argument – but this will get you verbose output of every class in the system.

Categories: Internals, Java Tags: ,

Testing a large variance of inputs using Parameterized JUnit tests

April 17, 2013 4 comments

Often in utility methods (e.g. your usual StringUtils) you find yourself writing the same test over and over again with different inputs.
You can do something like this:

public class TestSomeUtils
{
      @Test
      public void test_function1_input_1()
      {
            test_function1("some-output",  7, 2.6);
      }

      @Test
      public void test_function1_input_2()
      {
            test_function1("another-output",  9, -1.56);
      }

      @Test
      public void test_function1_input_3()
      {
            test_function1("no-output",  0, 768.2341);
      }

      private void test_function1(String expectedOutput, int inputA, double inputB)
      {
            String actualOutput = SomeUtils.function1(inputA, inputB);
            assertEquals(expectedOutput, actualOutput);
      }
}

However – JUnit has a much better way of doing it – org.junit.runners.Parameterized

@RunWith(Parameterized.class)
public class TestSomeUtils
{
      private String expectedOutput;
      private int inputA;
      private double inputB;

      @Parameters
      public static Collection<Object[]> prepareData()
      {
            Collection<Object[]> args = new ArrayList<Object[]>();

            args.add(new Object[]{"some-output",  7, 2.6});
            args.add(new Object[]{"another-output",  9, -1.56});
            args.add(new Object[]{"no-output",  0, 768.2341});

            return args;        
      }

      public TestSomeUtils(String expectedOutput, int inputA, double inputB)
      {
            this.expectedOutput = expectedOutput;
            this.inputA = inputA;
            this.inputB = inputB;
      }

      @Test
      public void testSomething()
      {
            String actualOutput = SomeUtils.function1(inputA, inputB);
            assertEquals(expectedOutput, actualOutput);
      }
}

Explenation:

@RunWith(Parameterized.class) tells the JUnit framework use a non-default test runner, in which case it is the Parameterized runner.
This runner will execute all the tests on all the given inputs. So if you have 3 test methods and nine sets of inputs – you actually get 27 distinct tests.

How does it do it?

  1. It calls the prepareData method since it is annotated with @Parameters.
  2. For each Object[] in the Collection it will instantiate the test class using the Object[] as constructor arguments (Using Reflection).
  3. It will execute all the test methods in the test class

Simple, isn’t it?

I use it mostly for simple utility methods that I want to cover from end to end, but I have also used it to execute other tests as well.

%d bloggers like this: