empty interfaces via reflection

A

Aryeh M. Friedman

Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])
 
R

Roedy Green

Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])

I would think you would have to modify the bytes of a the class file
to add the dummy interface and load it with your own class loader to
do that. There may be an easier way.
 
P

Patricia Shanahan

Aryeh said:
Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])

Have you considered aspect oriented programming, and AspectJ in
particular?

Patricia
 
A

Aryeh M. Friedman

Aryeh said:
Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])

Have you considered aspect oriented programming, and AspectJ in
particular?

For other projects yes but this is one has Java as one of it's
requirements
 
P

Patricia Shanahan

Aryeh said:
Aryeh said:
Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])
Have you considered aspect oriented programming, and AspectJ in
particular?

For other projects yes but this is one has Java as one of it's
requirements

AspectJ is not Java enough for the purpose? I believe the classes you
are operating on can be written in conventional Java. It is only the
code that imposes the checks and debugging that needs the AspectJ
extensions on top of Java.

Patricia
 
A

Aryeh M. Friedman

Aryeh said:
Aryeh M. Friedman wrote:
Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])
Have you considered aspect oriented programming, and AspectJ in
particular?
For other projects yes but this is one has Java as one of it's
requirements

AspectJ is not Java enough for the purpose? I believe the classes you
are operating on can be written in conventional Java. It is only the
code that imposes the checks and debugging that needs the AspectJ
extensions on top of Java.

The reason for saying this is it needs to be 100% backwards compatible
with Java (i.e. you do not need AsepectJ to run or maintain any
component except the ones mentioned)... reason it is a commerical open-
source unit testing framework for java and part of the marketing is
all our products are 100% java.
 
A

Aryeh M. Friedman

The reason for saying this is it needs to be 100% backwards compatible
In think it over I decided to post a high level summary of the
problem:

1. The framework has it's own standalone GUI see
http://www.flosoft-systems.com/thisTest_screens.php for screen shots

2. When clicking on "run tests" any recompiling done since the last
test run (either from with in the GUI or restarting the app) needs to
be honored

3. I currently solved item 2 in a very adhoc and bug prone way:
a. Have a custom class loader (see other treads) since the system
class loader will not honor
updated .class files
b. A side effect of using a custom class loader is you can not
directly cast to an instance created using the system class loader.
For example:

public class Main
{
public static void main(String[] args)
throws Throwable
{
ClassLoader loader=new MyClassLoader();
Class klass=loader.loadClass("MyClass");

MyClass m=(MyClass) klass.newInstance();
}
}

Produces:
Exception in thread "main" java.lang.ClassCastException: MyClass
cannot be cast to MyClass
at Main.main(Main.java:11)

Here is the support code:

import java.io.*;
import java.lang.reflect.*;

public class MyClassLoader extends ClassLoader
{
public Class loadClass(String name)
{
try {
if(name.startsWith("java."))
return super.loadClass(name);

FileInputStream fis=new FileInputStream(name
+".class");
byte[] b=new byte[fis.available()];

fis.read(b);
fis.close();

return defineClass(name,b,0,b.length);
} catch(Throwable e) {
e.printStackTrace();
}

return null;
}
}

public class MyClass
{
public MyClass()
{
ack=new Integer(0);
}

public Integer getAck()
{
return ack;
}

private int foo;
private Integer ack;
}

If you want more detail and the threads proving the correctness of the
code see:

http://groups.google.com/group/comp...3290dc92e74/0169c9ea83253940#0169c9ea83253940

http://groups.google.com/group/comp...b0f0a2ab367/f28ba3e0de4cc60f#f28ba3e0de4cc60f

One solution I have found to this problem (which I do in a adhoc and
bug baity way in the production code) is to create a second instance
of the class using the system class loader then copy the fields over
that way any getter/setter operates on stuff created by the system
class loader and not the custom class loader (this is fine because by
definition Unit tests only test the top level containing class).
Recently I have come up with the following experimental code to do
this is a more systematic way:

import java.lang.reflect.*;

public class Main
{
public static void main(String[] args)
throws Throwable
{
ClassLoader loader=new MyClassLoader();
Class klass=loader.loadClass("MyClass");

MyClass m=(MyClass) rebrand(MyClass.class,klass.newInstance());

// cast to make sure rebrand works
System.out.println((Integer) m.getAck());
}

public static Object rebrand(Class brand,Object obj)
throws Throwable
{
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass(brand.getCanonicalName());
Object real=klass.newInstance();

for(Field f:real.getClass().getDeclaredFields()) {
if(f.getType().isPrimitive())
continue;

Field oldField=obj.getClass().getDeclaredField(f.getName());
boolean fVis=f.isAccessible();
boolean oVis=oldField.isAccessible();

try {
f.setAccessible(true);
oldField.setAccessible(true);
} catch(Throwable e) {
// if for some reason we can't mod the accessibility skip it
continue;
}

f.set(real,oldField.get(obj));

f.setAccessible(true);
oldField.setAccessible(true);
}


return real;
}
}

The only problem remaining is to call rebrand when ever the class
under test returns a field (see the println for an example).

This is where the proxy comes in I basically wrap Proxy.invoke(....)
around all method calls and if the return type needs to be rebranded
(made by the custom classloader) it does so. This is safe because it
is conceptually illegal for a unit test to call any methods in the
returned value except to check it's values.
 
A

Aryeh M. Friedman

This is where the proxy comes in I basically wrap Proxy.invoke(....)
around all method calls and if the return type needs to be rebranded
(made by the custom classloader) it does so. This is safe because it
is conceptually illegal for a unit test to call any methods in the
returned value except to check it's values.

oops mentioned the one problem java.lang.reflect.Proxy requires all
acted on "classses" be interfaces not classes. thus the desire to
make a empty interface and wrap any rebranded class in it tempurarly
so the proxy can be used.
 
O

Owen Jacobson

oops mentioned the one problem java.lang.reflect.Proxy requires all
acted on "classses" be interfaces not classes. thus the desire to
make a empty interface and wrap any rebranded class in it tempurarly
so the proxy can be used.

You will discover that creating a proxy does not expose arbitrary
random method calls, nor can the proxy be (down)cast to any interface
other than the one you specified when it was created. Java's static
type checking still applies, preventing the former, and the object the
caller invokes methods on (the proxy) doesn't have the complete
inheritance hierarchy of the proxied object. For example, the
following won't work:

public interface Proxied {}

public class Foo implements Proxied {
public void bar () {...}
}

....
Foo proxyForFoo = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),
new Class[] { Proxied.class },
someHandler);
....

because the object returned from newProxyInstance is neither a Foo nor
a child of Foo.

In short, you can't get there from here; go back to working with class
loaders. I think you probably want to avoid running any user code
from the System classloader at all; if possible, you want to run each
test case inside a single classloader which can be thrown away at the
end of the run and which provides canonical definitions of each class
to the tested code.

The other traditional and, more importantly, workable tool for moving
objects' states between classloaders is serialization; obviously, this
only works if the objects in question are serializable. This is one
of the reasons EJB remote interfaces must accept only serializable
objects or primitives as arguments and only return said.
 
A

Aryeh M. Friedman

oops mentioned the one problem java.lang.reflect.Proxy requires all
acted on "classses" be interfaces not classes. thus the desire to
make a empty interface and wrap any rebranded class in it tempurarly
so the proxy can be used.

You will discover that creating a proxy does not expose arbitrary
random method calls, nor can the proxy be (down)cast to any interface
other than the one you specified when it was created. Java's static
type checking still applies, preventing the former, and the object the
caller invokes methods on (the proxy) doesn't have the complete
inheritance hierarchy of the proxied object. For example, the
following won't work:

public interface Proxied {}

public class Foo implements Proxied {
public void bar () {...}

}

...
Foo proxyForFoo = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),
new Class[] { Proxied.class },
someHandler);
...

because the object returned from newProxyInstance is neither a Foo nor
a child of Foo.

I was vaguely aware of that and was expecting something above the
proxy to unwrap before handing back the object.
In short, you can't get there from here; go back to working with class
loaders. I think you probably want to avoid running any user code
from the System classloader at all; if possible, you want to run each
test case inside a single classloader which can be thrown away at the
end of the run and which provides canonical definitions of each class
to the tested code.

That was my orginial thinking but some issues came up like how to
handle result reporting when the ui code couldn't do this easily:

Result res=test.getResult();

keep in mind the test is from MyClassLoader and the ui (which has
main()) is by definition uses SystemClassLoader
The other traditional and, more importantly, workable tool for moving
objects' states between classloaders is serialization; obviously, this
only works if the objects in question are serializable. This is one
of the reasons EJB remote interfaces must accept only serializable
objects or primitives as arguments and only return said.

Thats where I got stuck.... since it is a testing framework it *MUST*
work on anything including Object (in theory)
 
D

Daniel Pitts

Aryeh said:
oops mentioned the one problem java.lang.reflect.Proxy requires all
acted on "classses" be interfaces not classes. thus the desire to
make a empty interface and wrap any rebranded class in it tempurarly
so the proxy can be used.
What you really need to do is NOT cast to an explicit object, but use
reflection to call your test hooks:

Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();
for (Method method: testClass.getDeclaredMethods()) {
method.invoke(testInstance, new Object[0]);
}
 
A

Aryeh M. Friedman

oops mentioned the one problem java.lang.reflect.Proxy requires all
acted on "classses" be interfaces not classes. thus the desire to
make a empty interface and wrap any rebranded class in it tempurarly
so the proxy can be used.

What you really need to do is NOT cast to an explicit object, but use
reflection to call your test hooks:

Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();
for (Method method: testClass.getDeclaredMethods()) {
method.invoke(testInstance, new Object[0]);

}

Then how do you handle the return type?!?!?!? Namely I can't do:

Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();
Result res=new Result();

for (Method method: testClass.getDeclaredMethods())
res.merge((Result) method.invoke(testInstance, new
Object[0])); // cast exception

reportResults(res)

....

private void reportResults(Result res)
{
.....
}


The reason why it is not possible is any Result object created by a
test is <MyClassLoader>.Result and all the results here are
<SystemClassLoader>.Result
 
S

Steven Simpson

Aryeh said:
Then how do you handle the return type?!?!?!? Namely I can't do:

Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();
Result res=new Result();

for (Method method: testClass.getDeclaredMethods())
res.merge((Result) method.invoke(testInstance, new
Object[0])); // cast exception

The reason why it is not possible is any Result object created by a
test is <MyClassLoader>.Result and all the results here are
<SystemClassLoader>.Result

Looking back at an earlier post, your custom MyClassLoader goes like this:
public class MyClassLoader extends ClassLoader
{
public Class loadClass(String name)
{
try {
if(name.startsWith("java."))
return super.loadClass(name);

A custom ClassLoader is expected to override findClass(String) rather
than loadClass(String), as the latter (indirectly) accomplishes this
behaviour:

<http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html>

"When requested to find a class or resource, a ClassLoader instance will
delegate the search for the class or resource to its parent class loader
before attempting to find the class or resource itself."

MyClassLoader is loading Result instead of delegating to its parent
first, which should always find it first.
 
A

Aryeh M. Friedman

Aryeh said:
Then how do you handle the return type?!?!?!? Namely I can't do:
Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();
Result res=new Result();
for (Method method: testClass.getDeclaredMethods())
res.merge((Result) method.invoke(testInstance, new
Object[0])); // cast exception
The reason why it is not possible is any Result object created by a
test is <MyClassLoader>.Result and all the results here are
<SystemClassLoader>.Result

Looking back at an earlier post, your custom MyClassLoader goes like this:
public class MyClassLoader extends ClassLoader
{
public Class loadClass(String name)
{
try {
if(name.startsWith("java."))
return super.loadClass(name);

A custom ClassLoader is expected to override findClass(String) rather
than loadClass(String), as the latter (indirectly) accomplishes this
behaviour:

<http://java.sun.com/javase/6/docs/api/java/lang/ClassLoader.html>

"When requested to find a class or resource, a ClassLoader instance will
delegate the search for the class or resource to its parent class loader
before attempting to find the class or resource itself."

MyClassLoader is loading Result instead of delegating to its parent
first, which should always find it first.

I just tested:import java.io.*;
import java.lang.reflect.*;

public class MyClassLoader extends ClassLoader
{
public Class findClass(String name)
{
try {
//if(name.startsWith("java."))
// return super.loadClass(name);

FileInputStream fis=new FileInputStream(name
+".class");
byte[] b=new byte[fis.available()];

fis.read(b);
fis.close();

return defineClass(name,b,0,b.length);
} catch(Throwable e) {
e.printStackTrace();
}

return null;
}

and now the class loader no longer honors recompiled classes:

Script started on Sun Oct 14 15:09:05 2007
jtest@monster:/home/jtest% java Main
1
^Z
Suspended
jtest@monster:/home/jtest% cat foo
import java.lang.reflect.*;

public class MyClass
{
public MyClass()
{
ack=new Integer(2);
}

public Integer getAck()
{
return ack;
}

private int foo;
private Integer ack;
}
jtest@monster:/home/jtest% cp foo MyClass.java
jtest@monster:/home/jtest% javac MyClass.java
jtest@monster:/home/jtest% fg
java Main


1
^C
jtest@monster:/home/jtest% exit
Script ends on Sun Oct 14 15:09:45 2007

Just for ref here is the new main():

public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=new MyClassLoader();
Class klass=loader.loadClass("MyClass");

MyClass m=(MyClass) klass.newInstance();

System.out.println(m.getAck());
System.in.read();
}
}
}
 
S

Steven Simpson

Aryeh said:
I just tested:import java.io.*;
import java.lang.reflect.*;

public class MyClassLoader extends ClassLoader
{
public Class findClass(String name)

and now the class loader no longer honors recompiled classes:

while(true) {
ClassLoader loader=new MyClassLoader();
Class klass=loader.loadClass("MyClass");

MyClass m=(MyClass) klass.newInstance();

By this point at least, you'll have surely caused the system classloader
to load in MyClass itself (by referring to it in code), so later
MyClassLoaders will defer to that.

But this is just a test program right? In your other code, you had:

Class<?> testClass = loadTestClass();
Object testInstance = testClass.newInstance();

....and you don't actually refer to MyClass. So, as long as MyClass is
not in the program's classpath, the system classloader won't load it;
but your custom classloader will, if it looks in the right directory.

Going back to your test program to verify, you could just keep 'm' as an
Object, and invoke reflectively, also keeping MyClass out of the
classpath. Does that help?
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Aryeh said:
Aryeh said:
Aryeh M. Friedman wrote:
Is it possible to force a class to implement a (empty) interface via
reflection only... the problem is I want to create a Proxy but want
the class/interface being proxied to be totally unaware of it (eg.
TestProxy does some debugging and checks on all classes
Class.newInstance() calls after it is constructor is called [from the
caller not from within itself])
Have you considered aspect oriented programming, and AspectJ in
particular?
For other projects yes but this is one has Java as one of it's
requirements
AspectJ is not Java enough for the purpose? I believe the classes you
are operating on can be written in conventional Java. It is only the
code that imposes the checks and debugging that needs the AspectJ
extensions on top of Java.

The reason for saying this is it needs to be 100% backwards compatible
with Java (i.e. you do not need AsepectJ to run or maintain any
component except the ones mentioned)... reason it is a commerical open-
source unit testing framework for java and part of the marketing is
all our products are 100% java.

I still can not really see any reason why not to use AspectJ.

Yes - you need to distribute the aspectrt.jar, but most Java apps
require some jars.

Yes - developers will need the AspectJ tools, but they also need
an editor, a Java compiler etc..

Arne
 
L

Lew

Arne said:
I still can not really see any reason why not to use AspectJ.

Yes - you need to distribute the aspectrt.jar, but most Java apps
require some jars.

Yes - developers will need the AspectJ tools, but they also need
an editor, a Java compiler etc..

Be careful which version of AspectJ you use. Apparently some older versions
had trouble in multi-threaded, multi-processor environments. I have heard
that these troubles were repaired in the latest release(s).

It is also true that AspectJ defines a superset language to Java, which may be
the OP's concern with it. They do take care to maintain complete binary
compatibility with "plain" Java, though.

Still, I don't think you should minimize the differences from "plain ol' Java"
that AspectJ does introduce to the language. Perhaps they are worthwhile, but
the OP is correct to investigate the impact of these differences.

Disclaimer: I am not anything but superficially familiar with AspectJ,
although I did review their documentation as I wrote this post.
 
G

Guest

Lew said:
Be careful which version of AspectJ you use. Apparently some older
versions had trouble in multi-threaded, multi-processor environments. I
have heard that these troubles were repaired in the latest release(s).

It is also true that AspectJ defines a superset language to Java, which
may be the OP's concern with it. They do take care to maintain complete
binary compatibility with "plain" Java, though.

Still, I don't think you should minimize the differences from "plain ol'
Java" that AspectJ does introduce to the language. Perhaps they are
worthwhile, but the OP is correct to investigate the impact of these
differences.

AspectJ takes a valid class file and convert it to another
valid class file based on input from a source text file. The
resulting code requires a single jar file to be in
classpath.

The concept and syntax understanding to be able to write that
source text file has a steep learning curve.

But from a runtime perspective it has less impact to use AspectJ
than to use another XML parser than the one Java comes with.

Arne
 
G

Guest

Arne said:
AspectJ takes a valid class file and convert it to another
valid class file based on input from a source text file. The
resulting code requires a single jar file to be in
classpath.

The concept and syntax understanding to be able to write that
source text file has a steep learning curve.

But from a runtime perspective it has less impact to use AspectJ
than to use another XML parser than the one Java comes with.

I just refreshed:

.... takes a valid java file and convert it to a valid class file
based on ...

Arne
 
G

Guest

Arne said:
I just refreshed:

... takes a valid java file and convert it to a valid class file
based on ...

But to quote what they write themselves in
http://www.eclipse.org/aspectj/doc/next/devguide/ajc-ref.html:

<quote>
Compatibility

AspectJ is a compatible extension to the Java programming language. The
AspectJ compiler adheres to the The Java Language Specfication, Second
Edition and to the The Java Virtual Machine Specification, Second
Edition and runs on any Java 2 compatible platform. The code it
generates runs on any Java 1.1 or later compatible platform. For more
information on compatibility with Java and with previous releases of
AspectJ, see AspectJ Version Compatibility.
</quote>

And the link points to:
http://www.eclipse.org/aspectj/doc/next/devguide/compatibility.html
which further explains.

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top