Another reminder of java reflection

Java reflection is powerful, but there are much more things to watch out.

I went into below error when invoke a method using reflection:

java.lang.IllegalArgumentException: object is not an instance of declaring class

It take me almost one whole day to find out the reason, that is I invoke method on class loaded from different Class loader, although the Class looks like the same.

Tip:

When debugging Java code in eclipse, every variable has a (id=**) at the end. It can be used to determine if tow objects, including Class, are the same one.

Advertisements

Switch to WordPress

I know WordPress is far better than MS live space, I didn’t make the change simply because I am lazy. I should say thank you to MS for the tolerable service all these years, and this easy and smooth migration to WordPress.

PS. I know this migration from CCTV news broadcast, not from Internet:)


Compile Objective-c on Ubuntu

Some tips I got after hours of experiments:

1. The “gcc -framework cocoa” does not work on linux.
2. The name of the makefile have to be “GNUmakefile”.

Here is a sample GNUmakefile:

include $(GNUSTEP_MAKEFILES)/common.make
TOOL_NAME = Go
Go_OBJC_FILES = main.m Person.m
Go_HEADER_FILES=Person.h
ADDITIONAL_CPPFLAGS=-Wall -Wno-import
include $(GNUSTEP_MAKEFILES)/tool.make


Vim for Objective-c

There are so many posts on this topic already, so I’ll simply make my own conclusion:

1. Install cocoa.vim:   unzip cocoa.zip -d ~/.vim
This include Objective-C filetype and syntax.

2. Install snipMate:  unzip snipMate.zip -d ~/.vim
This include Objective-C snippets

3. Set filetype for .h and .m file
echo "au BufNewFile,BufRead *.h,*.m    set filetype=objc" > ~/.vim/ftdetect/objc.vim


Watch out “this”, and you won’t get lost

I have gone through a painful afternoon just because I mess up with “this”. Let me tell you what has happened.

I’ll put it in the simplest form: I have a class “Invoker”, it simply invoke all methods of a object.

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class Invoker {
    public void invoke(Object obj) {
        Method[] methods = obj.getClass().getDeclaredMethods();
        for(Method m: methods){
            try {
                m.invoke(obj);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

and here is ClassA which has two methods just print their names.

public class ClassA {
    public void m1(){
        System.out.println("m1");
    }
    
    public void m2(){
        System.out.println("m2");
    }
    
    public void run(Invoker invoker){
        invoker.invoke(this);
    }
}

With these two classes, I could at least prove I am not doing anything wrong by run this line:

new ClassA().run(new Invoker());
 
outputs:
m1
m2

OK, it works. Now there comes ClassB, it want do something different in method m1 while still keep using the implementation of ClassA.m2

public class ClassB extends ClassA {
    public void m1(){
        System.out.println("m1_sub");
    }
}

Let’s run ClassB

new ClassB().run(new Invoker());
 
output:
m1_sub

Ooops, where is the output of method m2? why m2 is not working anymore? Isn’t ClassB.m2 inherited the ClassA.m2?  Why m2 stop working while run is still working?

Yes, ClassB is inherit from ClassA, that’s the reason why we could still get some output because run method of ClassB is still working. Remember we are not directly calling m2, but by reflection. Let’s look at the run method:

public void run(Invoker invoker){
    invoker.invoke(this);
}

The run method takes in a instance of Invoker and run it with “this”. So when we call run on ClassB, the Invoker.invoke method call with a instance of ClassB, and because this is no m2 defined on ClassB, there is actually no m2 method call in the call of of Invoker.invoke.

Phew~

But knowing m2 won’t get things any better, we still need to reuse the default implementations of ClassA, what should we do? It won’t be a problem if I have made myself understood: Implement the m2 method and call its super class’s method. So our ClassB finally looks like this:

public class ClassB extends ClassA {
    public void m1(){
        System.out.println("m1_sub");
    }
    
    public void m2(){
        super.m2();
    }
}

To summary, take care of “this” when subclassing a Class involved in reflection.


The use of parameter to block

Consider these two examples:

class Object
  def convert(filename)
    args ||= {}
    args[:to] = filename
    args = yield(args)
  end
end

class Hash  
  def seek(pos)
    self[:seek] = pos
    self
  end
  def duration(length)
    self[:duration] = length
    self
  end
end

convert "findinng.avi" do |args|
  args.seek '00:01:13'
  args.duration '00:10:01'
end
class Object
  def convert(filename)
    @args ||= {}
    @args[:to] = filename
    yield
  end
  
  def seek(pos)
    @args[:seek] = pos
  end
  def duration(length)
    @args[:duration] = length
  end
end

convert "findinng.avi" do
  seek '00:01:13'
  duration '00:10:01'
end

Block scope in Ruby

Watch this code run, if you still mad about ruby block.

class Test
  def redefine_a(change, &block)
    a = "value for redefine_a"
    puts "before call block: #{eval("a", block.binding)}"
    if change
      a = block.call.to_s
    else
      block.call.to_s
    end
    puts "after call block: #{eval("a", block.binding)}"
    return "returned from redefined_a: #{a}"
  end
end
 
class Invoker
  def self.invoke
    a = "original"
    puts Test.new.redefine_a(false) {a = "changed_1"}
    puts Test.new.redefine_a(true) {a = "changed_2"}
  end
end
 
Invoker.invoke