Skip to main content

Catch-Up 01 May, 2010

ยท 16 min read

Some part of [3. Bug in Java compiler?Shadowing Declarations?](#3. Shadowing Declarations?) is updated twice on the 10th of May in 2010.

I have been very busy and am still busy so haven't written anything for quite a while on my blog except for those entries with only one or two sentences. So I'm quickly writing what I do these days and some issues I have dealt with.

1. Issue with the new m2eclipse (version: 0.10.0.20100209-0800)โ€‹

Sonatype released the new version of m2eclipse in February 2010. Since I updated with it, I had got some problem with maven build through Hudson.

The new version of m2eclipse comes with maven3 embedded yet my server uses maven2 so does my Linux on my Desktop PC. So it was only m2eclipse which uses maven3 (SNAPSHOT version) and I deployed some of my libraries used in one web application development project. Problem was that I deployed the dependency libraries several times with the same version number. With maven2, it's OK as it uses time-stamp to distinguish one version from another within the same version, yet with maven3, having the same version is not allowed. Well, I am not 100% sure about this as once I solved the problem I didn't really check the details as I didn't have enough time. Anyway, so as shown in the following image, the project status icon once became dark rain clouds which mean really bad.

Build Failure: Project status icon became dark rain clouds Build Failure: Project status icon became dark rain clouds

My project build failed seven times due to the difference between maven2 and maven3 I described above, or it can be something else yet it is caused by some difference between those two versions.

Build Failure: It failed seven times due to the difference between maven2 and maven3 Build Failure: It failed seven times due to the difference between maven2 and maven3

(It happened in February. The build number in the image is 108 but it is now 305).

So why did I not just keep the old version of m2eclipse with maven2 embedded? Well, the old one comes with some old version of maven2 which does not support password encryption while the maven2 on both my PC and my server does support it as it is a newer version. Thus I updated with the new m2eclipse as soon as it was available yet didn't really expect that it comes with maven3. Anyway, It's solved by using maven2 installed on my PC when deploying project packages. The other times such as solving dependencies and building package without deployment, I can still use the embedded maven3 in the new m2eclipse without any problems.

2. I have been working on...โ€‹

I founded a start-up company with my friend a few months ago, and we are currently working on a web application development for our own start-up, but it is probably too premature to announce what it is as it's still an early stage of development. The issues listed in the following image is a part of the issues I and my colleague have solved and been working on.

I'm currently working on this project. I'm currently working on this project.

In addition, I have been developing my own Java libraries which can be commonly used in many other projects (and my friend has also been developing reusable JavaScript libraries). However, I did not record all the issues belong to these reusable components and recently felt that I should do it before I go any further. Otherwise, I may later forget what problems I solved and how I did as well as all the issues covered previously. So I wrote all the tickets for those libraries.

Issues of commonly used libraries built by myself

Issues of commonly used libraries built by myself

I've also been developing 'Java object to JSON' library and did the same as what I just explained (that is creating issue tickets). There are already a number of the libraries which convert Java object into JSON so why would I make another? Well, there can be several reasons but major ones are

  1. I need it to convert any POJO with only annotations into JSON.
  2. It has to be simple as I do not want to have any complex functions or heavy library for a simple conversion (some libraries are too heavy for such a simple task).
  3. When customisation is required or bug is found in the library, I want to be able to change and fix it however I want so that I do not have to waste my time on waiting for others to solve it.
  4. I want it to work in some environments where using bytecode manipulation is not an option. So if I programme one with bytecode manipulation then it works faster when it's available whereas the other one is without it so that it can be used in those enviornments (I currently have only the latter one and will do the former one when I have time later).

The following issues are what I have solved for the Java to JSON library.

Issues of my Java object to JSON library Issues of my Java object to JSON library

Finally, I have another project to help Ajax enabled web application development. From my experience, I found that it is sharing the information about the available server-side functions with the client-side developers that causes the most waste of time between the front-end development and the back-end development. The first time one function is made or whenever the existing ones are changed, I have to write or rewrite the document explaining it and the client-side developer has to find the changed parts in the document. It is annoying and a non-productive moment in the development so I and my colleague discussed about this issue and came up with the idea of having a library which exposes all the available server-side functions to the front-end (It can understand Spring @MVC controllers). For now, it has only this, yet I will add more features to help Ajax web application development.

Issues of my web method library Issues of my web method library

  • As I used more and more reflection to develop those libraries, I realised that Java Reflection has no method to get the names of method parameters. Well, there can be some ways for instance, using -g (generating debugging info) option when compiling or using some libraries such as ASM or use ParaNamer (It requires an additional step when compiling to add the constants having the parameter names in the class) but not by just Java reflection. Anyway, none of these is the solution I want, and unfortunately if I heard right, this problem will remain in JDK 7. ๐Ÿ˜ž

3. Bug in Java compiler? Shadowing Declarations?โ€‹

I created the Objects utility class based on http://download.java.net/jdk7/docs/api/java/util/Objects.html. This will be available in JDK 7 yet I wanted to use it before JDK 7 is released so I made my own one. I can use it now, and it can easily be replaced by the one in JDK when it's available. After I made it, I found some weird bug, I believe, in Java compiler. After I used it, I had some problem and thought it could be a bug in Java compiler yet it looks like 'shadowing declarations'.

This is the part of Objects class I coded.

package com.lckymn.kevin.common.util;

/**
* @author Lee, SeongHyun (Kevin)
* @version 0.0.1 (2010-04-30)
*/
public final class Objects {
private Objects() {
throw new IllegalStateException(getClass().getName() +
" cannot be instantiated.");
}

// other code omitted ...

/**
* Returns the hash code of a non-{@code null} argument
* and 0 for a {@code null} argument.
*
* @param o an object
* @return the hash code of a non-{@code null} argument
* and 0 for a {@code null} argument
* @see {@link Object#hashCode()}
*/
public static int hashCode(final Object o) {
return (null == o ? 0 : o.hashCode());
}

// other code omitted ...
}

The following code is a POJO in which I want to use the Objects.hashCode(Object) method.

package com.lckymn.kevin.test.bean;

/**
* @author Lee, SeongHyun (Kevin)
* @version 0.0.1 (2010-04-30)
*/
public class SomePojo {
private final int number;
private final String name;

public SomePojo(int number, String name) {
this.number = number;
this.name = name;
}

public int getNumber() {
return number;
}

public String getName() {
return name;
}

@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + number;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

@Override public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof SomePojo)) {
return false;
}
final SomePojo that = (SomePojo) obj;
return (this.number == that.getNumber()) &&
(this.name == that.getName() ||
(null != this.name && this.name.equals(that.getName()))
);
}
}

So I changed this code snippet

@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + number;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}

to this.

package com.lckymn.kevin.test.bean;

import static com.lckymn.kevin.common.util.Objects.*;

public class SomePojo {
// ...

@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + number;
result = prime * result + hashCode(name);
return result;
}
}

I used static import and hashCode(Object) method in the Objects class. Although, nothing's wrong in the code, my Eclipse complains that there is a compile-time error. The following image shows that.

Objects.hashCode(Object) with static import does not work. Objects.hashCode(Object) with static import does not work.

Yet the same code with no-static import but using class name as the qualifier to use hashCode(Object) method works perfectly. The following code has Objects.hashCode(name) and no compile-time error.

package com.lckymn.kevin.test.bean;

import com.lckymn.kevin.common.util.Objects;

/**
* @author Lee, SeongHyun (Kevin)
* @version 0.0.1 (2010-04-30)
*/
public class SomePojo {
private final int number;
private final String name;

public SomePojo(int number, String name) {
this.number = number;
this.name = name;
}

public int getNumber() {
return number;
}

public String getName() {
return name;
}

@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + number;
result = prime * result + Objects.hashCode(name);
return result;
}

@Override public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (null == obj) {
return false;
}
if (!(obj instanceof SomePojo)) {
return false;
}
final SomePojo that = (SomePojo) obj;
return (this.number == that.getNumber()) &&
(this.name == that.getName() ||
(null != this.name && this.name.equals(that.getName()))
);
}
}

The following image shows it has no error in the part where Objects.hashCode(Object) is used..

Using Class as qualifier to use hashCode works. Using Class as qualifier to use hashCode works.

I wondered if it's a bug in the Eclipse or a bug in the Java compiler. So I opened the terminal and tested it.

$ javac -version
javac 1.6.0_15


$ javac com/lckymn/kevin/test/bean/SomePojo.java
com/lckymn/kevin/test/bean/SomePojo.java:39: cannot find symbol
symbol : method hashCode(java.lang.String)
location: class com.lckymn.kevin.test.bean.SomePojo
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: operator + cannot be applied to int,hashCode
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: incompatible types
found : <nulltype>
required: int
result = prime * result + hashCode(name);
^
3 errors

As it shows, the compiler does totally not understand that the hashCode(Object) method from the Objects class is available and valid.

Is a bug only in the SUN JDK in the Ubuntu Linux repository? So I tried with OpenJDK 6 as well.

$ /usr/lib/jvm/java-6-openjdk/bin/javac -version
javac 1.6.0_0

$ /usr/lib/jvm/java-6-openjdk/bin/javac com/lckymn/kevin/test/bean/SomePojo.java
com/lckymn/kevin/test/bean/SomePojo.java:39: cannot find symbol
symbol : method hashCode(java.lang.String)
location: class com.lckymn.kevin.test.bean.SomePojo
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: operator + cannot be applied to int,hashCode
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: incompatible types
found : <nulltype>
required: int
result = prime * result + hashCode(name);
^
3 errors

The same result...

OK, it might be a bug in that particular version. Fortunately, the most recent version of SUN JDK 6 was released yesterday. It was officially released before (the 15th of April, 2010) yet the version managed by Ubuntu was not available before yesterday. So I installed it and tested it again with the Java compiler in the new JDK6. New version of SUN JDK6 is available in the Ubuntu repository

It still has the same problem.

$ javac -version
javac 1.6.0_20

$ javac com/lckymn/kevin/test/bean/SomePojo.java
com/lckymn/kevin/test/bean/SomePojo.java:39: cannot find symbol
symbol : method hashCode(java.lang.String)
location: class com.lckymn.kevin.test.bean.SomePojo
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: operator + cannot be applied to int,hashCode
result = prime * result + hashCode(name);
^
com/lckymn/kevin/test/bean/SomePojo.java:39: incompatible types
found : <nulltype>
required: int
result = prime * result + hashCode(name);
^
3 errors

I probably need to test with the Java compiler in the JDK6 for Windows but I have no stomach for that now nor do I have time to do that.

  • Update1 (2010-05-10)

    I also tested it with the Java compiler in the JDK 6 (1.6.0_16) for Windows and got the same result. It seem like static import cannot handle method overloading. I didn't have time to research to find the details but based on my testing, method overloading cannot be used with static import. If so then there should be a good reason for that, and the only one I can think of right now is that it might have something to do with varargs. Take a look at the following code.

    package com.lckymn.kevin.common.util;

    public final class SomeHelper {
    private SomeHelper() {
    throw new IllegalStateException(getClass().getName() + " cannot be instantiated.");
    }

    public static void test(Object... object) {
    System.out.println("SomeHelper.test()");
    }
    }
    package com.lckymn.kevin.test;

    import static com.lckymn.kevin.common.util.SomeHelper.test;

    public class Test {
    public void test() {
    System.out.println("Test.test()");
    }

    public void callTest() {
    test(); // no error here.

    Object object = new Object();
    test(object); // compile-time error
    }
    }

    Since a method with varargs can take no argument when it's called, Test.test() and SomeHelper.test(Object... object) can be indistinguishable with static import. This is, I think, probably one of the reasons why method overloading is not allowed with static import. Nevertheless, it is still very weird as calling test() does not cause any compile-time error while test(object) does. So the following code has no compile-time error and displays Test.test().

    package com.lckymn.kevin.test;

    import static com.lckymn.kevin.common.util.SomeHelper.test;

    public class Test {
    public void test() {
    System.out.println("Test.test()");
    }

    public void callTest() {
    test(); // static import of SomeHelper.test has no effect here.
    }

    public static void main(String[] args) {
    new Test().callTest();
    System.exit(0);
    }
    }

    It displays Test.test().

    What if the helper class has test() method with no arguments and the Test class has test() method with varargs then call test()? The same result! It still calls Test's test() method with varargs (Test.test(Object... object)).

    package com.lckymn.kevin.common.util;

    public final class SomeHelper {
    private SomeHelper() {
    throw new IllegalStateException(getClass().getName() + " cannot be instantiated.");
    }

    public static void test() {
    System.out.println("SomeHelper.test()");
    }
    }
    package com.lckymn.kevin.test;

    import static com.lckymn.kevin.common.util.SomeHelper.test;

    public class Test {
    public void test(Object... object) {
    System.out.println("Test.test(Object...object)");
    }

    public void callTest() {
    test(); // it calls the Test.test(Object... object) method NOT SomeHelper.test().
    }

    public static void main(String[] args) {
    new Test().callTest();
    System.exit(0);
    }
    }

    It displays Test.test(Object...object)

    Update2 (2010-05-10)

    It is more likely to be 'Shadowing Declarations'. Although, I couldn't find the exactly matching case from the JLS yet, it makes more sense if the method imported by static-import is shadowed.

4. Using Objectsโ€‹

By the way, the Objects class is simple but very useful. with it, the highlighted parts of the following code can

package com.lckymn.kevin.test.bean;

public class Bank {
private Long id;
private String bankName;
private String bsbNumber;
private String address;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getBankName() {
return bankName;
}

public void setBankName(String bankName) {
this.bankName = bankName;
}

public String getBsbNumber() {
return bsbNumber;
}

public void setBsbNumber(String bsbNumber) {
this.bsbNumber = bsbNumber;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((bankName == null) ? 0 : bankName.hashCode());
result = prime * result + ((bsbNumber == null) ? 0 : bsbNumber.hashCode());
return result;
}

@Override
public boolean equals(Object bank) {
if (this == bank) {
return true;
}
if (!(bank instanceof Bank)) {
return false;
}
final Bank that = (Bank) bank;
return (this.bankName == that.getBankName() ||
(null != this.bankName && this.bankName.equals(that.getBankName()))
) && (
this.bsbNumber == that.getBsbNumber() ||
(null != this.bsbNumber && this.bsbNumber.equals(that.getBsbNumber()))
);
}
}

become like this

package com.lckymn.kevin.test.bean;

import com.lckymn.kevin.common.util.Objects;

public class Bank {
private Long id;
private String bankName;
private String bsbNumber;
private String address;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getBankName() {
return bankName;
}

public void setBankName(String bankName) {
this.bankName = bankName;
}

public String getBsbNumber() {
return bsbNumber;
}

public void setBsbNumber(String bsbNumber) {
this.bsbNumber = bsbNumber;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

@Override
public int hashCode() {
return Objects.hash(bankName, bankName);
}

@Override public boolean equals(Object bank) {
if (this == bank) {
return true;
}
if (!(bank instanceof Bank)) {
return false;
}
final Bank that = (Bank) bank;
return Objects.equals(this.bankName, that.getBankName()) &&
Objects.equals(this.bsbNumber, that.getBsbNumber());
}
}

So these five lines in the hashCode method

final int prime = 31;
int result = 1;
result = prime * result + ((bankName == null) ? 0 : bankName.hashCode());
result = prime * result + ((bsbNumber == null) ? 0 : bsbNumber.hashCode());
return result;

become

return Objects.hash(bankName, bankName);

and these four lines in the equals method

return (this.bankName == that.getBankName() ||
(null != this.bankName && this.bankName.equals(that.getBankName()))
) && (
this.bsbNumber == that.getBsbNumber() ||
(null != this.bsbNumber && this.bsbNumber.equals(that.getBsbNumber()))
);

become

return Objects.equals(this.bankName, that.getBankName()) &&
Objects.equals(this.bsbNumber, that.getBsbNumber());

Although one might say that I can use Lombok instead, I prefer to see what is going on in my code. Those hashCode and equals methods are not additional info of the class. It tells what makes instances of the class equal thus I prefer to have it in there to see and want to freely change it whenever and however I want. Well, in other words, just a matter of personal preference. ๐Ÿ™‚ That's it. I perhaps have more to say yet am getting tired (4:55 AM ๐Ÿ˜ฎ). So I'm calling it a night. ๐Ÿ™‚