Quantcast
Channel: Sleepless Dev
Viewing all articles
Browse latest Browse all 213

Added respondsTo, invoke from Ruby to Java (via Boon), and added Go Programming style interface support, and dynamic JSON, list, map marshaling

$
0
0

Wrote some code to speed up injection container construction and then went ahead and wrote some code to speed up the toList biz. Then wrote some additional code to speed up dynamic invoke

Then I've always wanted to add some nice reflection utilities to easily invoke/marshal to Java objects.  I wrote a Ruby style respondsTo method (cached methods, should be fairly fast). I also added JSON, List, and Map marshaling to Java method calls. 

The respondsTo works with no args, class as args parameter types and objects as arguments. 

Then on top of respondsTo I wrote Go Programming style interface support so you can have an interface and as long as you support all the methods in that interface, you object does not have to implement it. This is so you don't have to have 100 jar file dependencies for design by interface. Read up on Go Programming to see what I am talking about because I am not giving it justice. 

Considering writing a respondsTo that works with JSON, maps and lists like the Invoker/Marshaler (seen at bottom of this post). I am also considering adding the ability for invoke to calling   missingMethod(String methodName, Object... args):Object if the method can't be found and there is a missingMethod defined in the instance. :)

Please take a look at the Ruby style respondsTo in Java.


Added Ruby style respondsTo to Java

We can invoke methods if they are supported. (Duck typing in Java)
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);


for(Objectobject:list){
if(respondsTo(object,"open",String.class))invoke(object,"open","hi");

if(respondsTo(object,"add",int.class,int.class))puts("add",invoke(object,"add",1,2));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}

The above invokes openaddreadLine and close methods if they are found. Above we pass types to see if there is a match. You don't have to pass types, respondsTo can also just check to see if the method exists. The invoke operation should be fairly fast in a tight loop.
You have the option of invoking by argument type match without passing around types (classes) as follows:
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);


for(Objectobject:list){
if(respondsTo(object,"open","hi"))invoke(object,"open","hi");

if(respondsTo(object,"add",1,2))puts("add",invoke(object,"add",1,2));


if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}
You can also invoke with a java.util.List (invoke and respondsTo take var-arg Object... by default for arguments) as follows:
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);



List<?>openList=list("hi");
List<?>addList=list(1,2);

for(Objectobject:list){
if(respondsTo(object,"open",openList))invoke(object,"open",openList);

if(respondsTo(object,"add",addList))puts("add",invoke(object,"add",addList));


if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}

booleanok=file.closeCalled&&file.readLine&&file.openCalled&&file.addCalled||die();


I also added the ability to invoke by interface. This is a loosely typed interface concept like the Go Programming language in that the class does not have to implement the interface. It only has to implement the methods in the interface. This allows loosely coupled (no jar dependencies) contracts like Go, or so I hope.
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);



List<?>openList=list("hi");
List<?>addList=list(1,2);

for(Objectobject:list){
if(handles(object,FileInterface.class))invoke(object,"open",openList);

if(respondsTo(object,"add",addList))puts("add",invoke(object,"add",addList));


if(handles(object,FileInterface.class)){
puts(invoke(object,"readLine"));
puts(invoke(object,"readLine"));
invoke(object,"close");
}
}


Here is the complete code listing for handles and respondsTo:
packageorg.boon.core.reflection;


importorg.junit.Test;

importjava.io.BufferedReader;
importjava.io.IOException;
importjava.io.StringReader;
importjava.util.List;

importstaticorg.boon.Boon.puts;
importstaticorg.boon.Exceptions.die;
importstaticorg.boon.Lists.list;
importstaticorg.boon.Str.lines;
importstaticorg.boon.core.reflection.Reflection.handles;
importstaticorg.boon.core.reflection.Reflection.invoke;
importstaticorg.boon.core.reflection.Reflection.respondsTo;

publicclassRespondsTo{

publicstaticinterfaceFileInterface{
voidopen(StringfileName);

StringreadLine();

voidclose();
}


publicstaticclassFileObject{

booleanreadLine;
booleanopenCalled;
booleancloseCalled;

booleanaddCalled;

publicvoidopen(StringfileName){

openCalled=true;
puts("Open ",fileName);
}

publicStringreadLine(){
readLine=true;
return"read line";
}

publicintadd(inti,intf){
addCalled=true;
returni+f;
}

publicvoidclose(){
closeCalled=true;
}


}

publicstaticclassStringReaderThing{

BufferedReaderreader=null;

Stringcontents;

publicStringReaderThing(Stringcontents){
this.contents=contents;
}

publicvoidopen(StringfileName){

reader=newBufferedReader(newStringReader(contents));

}

publicStringreadLine()throwsIOException{
returnreader.readLine();
}

publicvoidclose()throwsIOException{
reader.close();
}

}



@Test
publicvoidtest(){
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);


for(Objectobject:list){
if(respondsTo(object,"open",String.class))invoke(object,"open","hi");

if(respondsTo(object,"add",int.class,int.class))puts("add",invoke(object,"add",1,2));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}

booleanok=file.closeCalled&&file.readLine&&file.openCalled&&file.addCalled||die();


}



@Test
publicvoidtestInvoke(){
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);


for(Objectobject:list){
if(respondsTo(object,"open","hi"))invoke(object,"open","hi");

if(respondsTo(object,"add",1,2))puts("add",invoke(object,"add",1,2));


if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}

booleanok=file.closeCalled&&file.readLine&&file.openCalled&&file.addCalled||die();



}


@Test
publicvoidtestInvokeByList(){
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);



List<?>openList=list("hi");
List<?>addList=list(1,2);

for(Objectobject:list){
if(respondsTo(object,"open",openList))invoke(object,"open",openList);

if(respondsTo(object,"add",addList))puts("add",invoke(object,"add",addList));


if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"readLine"))puts(invoke(object,"readLine"));

if(respondsTo(object,"close"))invoke(object,"close");
}

booleanok=file.closeCalled&&file.readLine&&file.openCalled&&file.addCalled||die();



}



@Test
publicvoidtestHandles(){
FileObjectfile=newFileObject();
StringReaderThingreader=newStringReaderThing(lines("Hi mom","how are you?"));
List<Object>list=list(file,reader);



List<?>openList=list("hi");
List<?>addList=list(1,2);

for(Objectobject:list){
if(handles(object,FileInterface.class))invoke(object,"open",openList);

if(respondsTo(object,"add",addList))puts("add",invoke(object,"add",addList));


if(handles(object,FileInterface.class)){
puts(invoke(object,"readLine"));
puts(invoke(object,"readLine"));
invoke(object,"close");
}
}

booleanok=file.closeCalled&&file.readLine&&file.openCalled&&file.addCalled||die();



}
}

Dynamic invocation via list, map, Json Map, and Json List

I added the ability to dynamic dispatch to a method from a map or list or JSON. This is important for REST, Websocket, Service and JSON messaging.
Take a look and see if you can figure out where I am going, then let me know because sometimes I forget.
packageorg.boon.core.reflection;

importorg.boon.Lists;
importorg.boon.Maps;
importorg.junit.Test;

importjavax.annotation.PostConstruct;


importstaticorg.boon.Boon.puts;
importstaticorg.boon.Boon.sputs;
importstaticorg.boon.Exceptions.die;

/**
* Created by Richard on 2/17/14.
*/
publicclassInvokerTest{


publicstaticclassHelloWorldArg{
inti=0;
Stringhello="null";

publicHelloWorldArg(inti){
this.i=i;
}

publicHelloWorldArg(inti,Stringhello){
this.i=i;
this.hello=hello;
}


publicHelloWorldArg(Stringhello){
this.hello=hello;
}

@Override
publicbooleanequals(Objecto){
if(this==o)returntrue;
if(o==null||getClass()!=o.getClass())returnfalse;

HelloWorldArgthat=(HelloWorldArg)o;

if(i!=that.i)returnfalse;
if(hello!=null?!hello.equals(that.hello):that.hello!=null)returnfalse;

returntrue;
}



@Override
publicinthashCode(){
intresult=i;
result=31*result+(hello!=null?hello.hashCode():0);
returnresult;
}
}

publicstaticclassHelloWorld{

booleaninitCalled;

booleancalled1st;
booleancalled2nd;



privateHelloWorldArgsayArg(HelloWorldArghi,inti){
returnhi;
}



privateHelloWorldArgsayArg2(HelloWorldArghi){
returnhi;
}

privatevoidsayHi(Stringhi){
puts("hi ",hi);

}



privateStringsay(Stringhi,inti){
returnsputs("hi ",hi,i);

}



privatevoidsayHi2(Stringhi){
called1st=true;
puts("hi ",hi);

}

privatevoidsayHi2(Stringhi,inti){
called2nd=true;

puts("hi ",hi);

}


@PostConstruct
privatevoidinit(){
initCalled=true;

}



}

@Test
publicvoidtest(){
Invoker.invoke(newHelloWorld(),"sayHi","Rick");
}



@Test
publicvoidtestPostConstruct(){
HelloWorldhw=newHelloWorld();
hw.initCalled=false;
Invoker.invokeMethodWithAnnotationNoReturn(hw,"postConstruct");
if(!hw.initCalled){
die("Post construct not called");
}
}


@Test
publicvoidtestPostConstruct2(){
HelloWorldhw=newHelloWorld();
hw.initCalled=false;
Invoker.invokeMethodWithAnnotationNoReturn(hw,"PostConstruct");
if(!hw.initCalled){
die("Post construct not called");
}
}


@Test
publicvoidtestPostConstruct3(){
HelloWorldhw=newHelloWorld();
hw.initCalled=false;
Invoker.invokeMethodWithAnnotationNoReturn(hw,"javax.annotation.PostConstruct");
if(!hw.initCalled){
die("Post construct not called");
}
}


@Test
publicvoidtestNoOverloads(){
try{
Invoker.invoke(newHelloWorld(),"sayHi2","Rick");
die("can't get this far");
}catch(Exceptionex){

}
}




@Test
publicvoidtestAllowOverloads(){
HelloWorldhw=newHelloWorld();
hw.called1st=false;
hw.called2nd=false;

Invoker.invokeOverloaded(hw,"sayHi2","Rick");

if((!hw.called1st)){
die("");
}


if((hw.called2nd)){
die("");
}
}




@Test
publicvoidtestAllowOverloads3(){
HelloWorldhw=newHelloWorld();
hw.called1st=false;
hw.called2nd=false;

Invoker.invokeOverloadedFromList(hw,"sayHi2",Lists.list("Rick"));

if((!hw.called1st)){
die("");
}


if((hw.called2nd)){
die("");
}
}



@Test
publicvoidtestAllowOverloads2(){
HelloWorldhw=newHelloWorld();
hw.called1st=false;
hw.called2nd=false;

Invoker.invokeOverloaded(hw,"sayHi2","Rick",1);

if((hw.called1st)){
die("");
}


if((!hw.called2nd)){
die("");
}
}



@Test
publicvoidtestAllowOverloads4(){
HelloWorldhw=newHelloWorld();
hw.called1st=false;
hw.called2nd=false;

Invoker.invokeOverloadedFromList(hw,"sayHi2",Lists.list("Rick","1"));

if((hw.called1st)){
die("");
}


if((!hw.called2nd)){
die("");
}
}



@Test
publicvoidtestWithListSimple(){
Invoker.invokeFromList(newHelloWorld(),"sayHi",Lists.list("Rick"));
}


@Test
publicvoidtestWithListSimple2(){
Stringmessage=(String)Invoker.invokeFromList(newHelloWorld(),"say",Lists.list("Rick",1));
puts(message);

if(!message.equals("hi Rick 1\n"))die(message);
}


@Test
publicvoidtestWithListSimpleWithConversion(){
Stringmessage=(String)Invoker.invokeFromList(newHelloWorld(),"say",Lists.list("Rick","1"));
puts(message);
if(!message.equals("hi Rick 1\n"))die(message);
}



@Test
publicvoidtestComplex(){
HelloWorldArgmessage=(HelloWorldArg)Invoker.invokeFromList(newHelloWorld(),"sayArg",
Lists.list(Lists.list("1","Hello"),1));


if(!message.equals(newHelloWorldArg(1,"Hello"))){
die();
}
}



@Test
publicvoidtestComplex2(){
HelloWorldArgmessage=(HelloWorldArg)Invoker.invokeFromObject(newHelloWorld(),"sayArg2",
Lists.list("1","Hello"));


if(!message.equals(newHelloWorldArg(1,"Hello"))){
die();
}
}



@Test
publicvoidtestComplex3(){
HelloWorldArgmessage=(HelloWorldArg)Invoker.invokeFromList(newHelloWorld(),"sayArg2",
Lists.list((Object)Lists.list("1","Hello")));


if(!message.equals(newHelloWorldArg(1,"Hello"))){
die();
}
}



@Test
publicvoidtestComplex4(){
HelloWorldArgmessage=(HelloWorldArg)Invoker.invokeFromList(newHelloWorld(),"sayArg2",
Lists.list(Maps.map("i","1","hello","Hello")));


if(!message.equals(newHelloWorldArg(1,"Hello"))){
die();
}
}



@Test
publicvoidtestComplex5(){
HelloWorldArgmessage=(HelloWorldArg)Invoker.invokeFromList(newHelloWorld(),"sayArg2",
Lists.list(Maps.map("i","1","hello","Hello")));


if(!message.equals(newHelloWorldArg(1,"Hello"))){
die();
}
}

}


Viewing all articles
Browse latest Browse all 213

Trending Articles