You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ant.apache.org by Aaron Kelley <ak...@ecsplus.com> on 2002/12/17 17:42:22 UTC

ClassFileSet method of loading classes

Does anyone know how the ClassFileSet determines a dependency?  I still
cannot get the ClassFileSet to work, so maybe it does not work how I
think it should.  I am not instantiating my classes directly.  Instead I
have a factory that will return an instance, given the class of the
Object.  Here is an example:
 
MyClass myclass = MyFactory.create(MyClass.class);
 
I would think that MyClass should be seen as a dependency (given that
this line exists in my rootfileset).  So am I using it wrong, or is it
something else?
 
Thanks,

Aaron

Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
> 
> Well, I don't know about Retroguard but if you want to experiment with 
> what dependencies can be gleaned from the bytecode, you could try the 
> <depend> task with the dump option set to see the output.
> 


So I did and found that the depend task is not able to handle our case.
Please refer to my mail at which I have attached the test case with the 
two classes and a build file. I added another target to the build file.
Once you have run the other test which creates Root.class and 
Dependency.class you can call

  build test-depend

This will touch Root.java and then run the depend task like this:

<depend closure="yes" destdir="." srcdir="." />

You will see that Root.class will be deleted but Dependency.class will 
survive.

Frank-Michael

Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Frank-Michael Moser wrote:
> 
> Do you know RetroGuard - an OpenSource obfuscator for Java?
> 
> http://www.retrologic.com/retroguard-main.html
> 
> This does definitely not handle MyClass.class notation as dependencies 
> and complains in its log file the usage of Class.forName(...) for all 
> upper cases. This was the starting point of my examinations.
> 

Well, I don't know about Retroguard but if you want to experiment with what 
dependencies can be gleaned from the bytecode, you could try the <depend> 
task with the dump option set to see the output.

Conor



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
> Frank-Michael Moser wrote:
> 
>>   Class.forName("package-of-myclass.MyClass");
>>
>> In fact, in bytecode it is coded much more near to the latter form, 
>> such that looking the bytecode can't result in finding any 
>> dependencies to MyClass.
> 
> 
> I'm not sure on what you are basing this information. ...
> 
> Looking at the bytecode will most certainly reveal a dependency on the 
> class MyClass. 

Do you know RetroGuard - an OpenSource obfuscator for Java?

http://www.retrologic.com/retroguard-main.html

This does definitely not handle MyClass.class notation as dependencies 
and complains in its log file the usage of Class.forName(...) for all 
upper cases. This was the starting point of my examinations.


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Frank-Michael Moser wrote:
> 
> When you examine at the bytecode of your (root-)class you will see that 
> writing
> 
>   MyClass.class
> 
> is totally equivalent to
> 
>   Class.forName("package-of-myclass.MyClass");
> 
> In fact, in bytecode it is coded much more near to the latter form, such 
> that looking the bytecode can't result in finding any dependencies to 
> MyClass.

I'm not sure on what you are basing this information. When the VM loads a 
class it looks through its class dependencies as defined in the constant 
pool entries. It may well use something similar to the Class.forName to 
actually load the classes but you will not see this in the bytecode at all. 
It all happens in the VM's class resolution code.

Looking at the bytecode will most certainly reveal a dependency on the class 
MyClass. It is not encoded as a string but as a class reference entry in the 
constant pool (which in turn uses a string).

Look at these elements for more info
http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#42041

Conor


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Aaron Kelley wrote:
> So how exactly are dependencies found then?  Are dependencies only found
> when you instantiate something with the keyword "new"?  My code is
> filled with objects that are instantiated from factories or services.
> If I simply return these objects from a service to my base code will my
> base code not see this class as a dependency?  I use these objects all
> throughout the base code, so I would imagine that they would be seen as
> such.

Of course they will be seen as dependencies and found at runtime by the 
virtual machine. But inspecting the bytecode you'll find only strings.

You could try to write your custom dependency collector which would be 
aware of these strings. (I'm not sure but I think I heard about such a 
tool) But keep in mind that this cannot cover all possible cases. In 
fact you can pass any string to a Java program at runtime and try to 
load a corresponding class - a bytecode inspector could never know about 
that.

> -----Original Message-----
> From: Frank-Michael Moser [mailto:moser@decodon.com] 
> Sent: Tuesday, December 17, 2002 11:05 AM
> To: Ant Users List
> Subject: Re: ClassFileSet method of loading classes
> 
> Aaron Kelley wrote:
> 
>> 
>>MyClass myclass = MyFactory.create(MyClass.class);
>> 
>>I would think that MyClass should be seen as a dependency (given that
>>this line exists in my rootfileset).  So am I using it wrong, or is it
>>something else?
> 
> 
> When you examine at the bytecode of your (root-)class you will see that 
> writing
> 
>    MyClass.class
> 
> is totally equivalent to
> 
>    Class.forName("package-of-myclass.MyClass");
> 
> In fact, in bytecode it is coded much more near to the latter form, such
> 
> that looking the bytecode can't result in finding any dependencies to 
> MyClass.
> 
> Some time ago, when I started to use an obfuscator, I ran into this 
> obstacle, too.
> 
> Frank-Michael
> 
> 
> --
> To unsubscribe, e-mail:
> <ma...@jakarta.apache.org>
> For additional commands, e-mail:
> <ma...@jakarta.apache.org>
> 
> 
> --
> To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
> For additional commands, e-mail: <ma...@jakarta.apache.org>


-- 
------------------------------------------------------------
DECODON GmbH                        phone: +49(0)3834 515231
W.-Rathenau-Str. 49a                  fax: +49(0)3834 515239
17489 Greifswald                    email: moser@decodon.com
Germany                               web:   www.decodon.com
------------------------------------------------------------


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


RE: ClassFileSet method of loading classes

Posted by Aaron Kelley <ak...@ecsplus.com>.
So how exactly are dependencies found then?  Are dependencies only found
when you instantiate something with the keyword "new"?  My code is
filled with objects that are instantiated from factories or services.
If I simply return these objects from a service to my base code will my
base code not see this class as a dependency?  I use these objects all
throughout the base code, so I would imagine that they would be seen as
such.

-----Original Message-----
From: Frank-Michael Moser [mailto:moser@decodon.com] 
Sent: Tuesday, December 17, 2002 11:05 AM
To: Ant Users List
Subject: Re: ClassFileSet method of loading classes

Aaron Kelley wrote:
>  
> MyClass myclass = MyFactory.create(MyClass.class);
>  
> I would think that MyClass should be seen as a dependency (given that
> this line exists in my rootfileset).  So am I using it wrong, or is it
> something else?

When you examine at the bytecode of your (root-)class you will see that 
writing

   MyClass.class

is totally equivalent to

   Class.forName("package-of-myclass.MyClass");

In fact, in bytecode it is coded much more near to the latter form, such

that looking the bytecode can't result in finding any dependencies to 
MyClass.

Some time ago, when I started to use an obfuscator, I ran into this 
obstacle, too.

Frank-Michael


--
To unsubscribe, e-mail:
<ma...@jakarta.apache.org>
For additional commands, e-mail:
<ma...@jakarta.apache.org>


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Aaron Kelley wrote:
>  
> MyClass myclass = MyFactory.create(MyClass.class);
>  
> I would think that MyClass should be seen as a dependency (given that
> this line exists in my rootfileset).  So am I using it wrong, or is it
> something else?

When you examine at the bytecode of your (root-)class you will see that 
writing

   MyClass.class

is totally equivalent to

   Class.forName("package-of-myclass.MyClass");

In fact, in bytecode it is coded much more near to the latter form, such 
that looking the bytecode can't result in finding any dependencies to 
MyClass.

Some time ago, when I started to use an obfuscator, I ran into this 
obstacle, too.

Frank-Michael


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
> 
> No, I think that would involve the halting problem :-). My fix is most 
> likely compiler-specific and depends on how the compiler names the 
> implicit Class instances. Maybe not that desirable.
> 
> Let me know what you think.
> 

I just checked out and built most recent Ant 1.5.9. Using the default 
modern compiler of JDK 1.4 work fine for classfileset with my small test 
case.

The behaviour of the depend task seems not to be touched at all - it 
does not pick up Dependency.class. But I assume this shouldn't be 
expected so far, didn't it?

If you whish a certain case to be tested, so let me know.

What do you think will there be a complete compiler-independent solution 
for this problem. I guess it should only rely on the Java-Bytecode 
specification. If so I would like to encourage the Retroguard people to 
apply your patch (or its idea), too.

Frank-Michael


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Frank-Michael Moser wrote:
> 
> This would be nice, I will test it...

OK, I've committed it now.

> 
> What do you have in mind for patching this case - testing whether a 
> string given to Class.forName(...) forms a valid class-name or something 
> similar?

No, I think that would involve the halting problem :-). My fix is most 
likely compiler-specific and depends on how the compiler names the implicit 
Class instances. Maybe not that desirable.

Let me know what you think.

Conor


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
> Frank-Michael Moser wrote:
>
>> But now I do.
> 
> Cast iron ? :-)

Not on you or anybody, of course ;)

> I've done some experiments with changes to ClassfileSet to pickup the 
> dependency. I think it is possible. I'll do some further testing before 
> I commit it (I need to add some code for inner classes). Want to test it?
> 

This would be nice, I will test it...

What do you have in mind for patching this case - testing whether a 
string given to Class.forName(...) forms a valid class-name or something 
similar?

Frank-Michael


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Frank-Michael Moser wrote:
> 
> But now I do.

Cast iron ? :-)

OK, I now see what you mean. I agree that ClassfileSet wil not pickup this 
dependency.

I've done some experiments with changes to ClassfileSet to pickup the 
dependency. I think it is possible. I'll do some further testing before I 
commit it (I need to add some code for inner classes). Want to test it?

Conor

> 
> BTW:
> Notice that javac of course handles Dependency as a dependency of Root 
> (parsing the source code). But not <classfileset...> can't.
> 

We'll see.

Conor



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
>> Should...?!
> 
> 
> Sure. I don't give cast-iron guarantees :-)

But now I do.

To prove I attached two Java classes (Root.java and Dependency.java) and 
a build.xml where the Root class is the root of a classfileset which 
later is used in a jar task. Root holds a reference to Dependency.class:

  public Class dependency = Dependency.class;

Put the three files into a single folder and run

  build deps

See what's in the jar.

Frank-Michael

BTW:
Notice that javac of course handles Dependency as a dependency of Root 
(parsing the source code). But not <classfileset...> can't.


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
>> Should...?!
> 
> 
> Sure. I don't give cast-iron guarantees :-)

But now I do.

To prove I attached two Java classes (Root.java and Dependency.java) and
a build.xml where the Root class is the root of a classfileset which
later is used in a jar task. Root holds a reference to Dependency.class:

   public Class dependency = Dependency.class;

Put the three files into a single folder and run

   build deps

See what's in the jar.

Frank-Michael

BTW:
Notice that javac of course handles Dependency as a dependency of Root
(parsing the source code). But not <classfileset...> can't.


Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Frank-Michael Moser wrote:
> Conor MacNeill wrote:
> 
>>> I would think that MyClass should be seen as a dependency (given that
>>> this line exists in my rootfileset).  
>>
>>
>>
>> This will show up as a dependency (a class reference). It should be 
>> picked up.
>>
> 
> Should...?!

Sure. I don't give cast-iron guarantees :-)

Conor




--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Frank-Michael Moser <mo...@decodon.com>.
Conor MacNeill wrote:
>> I would think that MyClass should be seen as a dependency (given that
>> this line exists in my rootfileset).  
> 
> 
> This will show up as a dependency (a class reference). It should be 
> picked up.
> 

Should...?!



--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>


Re: ClassFileSet method of loading classes

Posted by Conor MacNeill <co...@cortexebusiness.com.au>.
Aaron Kelley wrote:
> Does anyone know how the ClassFileSet determines a dependency? 

I do :-)

ClassFileSet works as follows. Firstly it determines a set of root classes. 
This is either the single class specified by a root element or the set 
classes included in a rootfileset.

These root classes are used as the starting points for the dependency 
search. ClassfileSet uses BCEL to analyze each class. The bytecode for each 
class includes a structure known as the constant pool which contains 
structures such as classrefs, method refs and fieldrefs. Each of these 
identifies another class upon which the class depends. All of these refs are 
gathered up as the dependencies of the class being examined. These are 
examined in turn until the closure of all dependencies is achieved.

The search is limited to classes within the classfileset's basedir. The 
includes element on the classfileset is not used - it is ignored.

When the classfileset is scanned the root classes and their dependencies are 
returned.

> I still
> cannot get the ClassFileSet to work, so maybe it does not work how I
> think it should.  I am not instantiating my classes directly.  Instead I
> have a factory that will return an instance, given the class of the
> Object.  Here is an example:
>  
> MyClass myclass = MyFactory.create(MyClass.class);
>  
> I would think that MyClass should be seen as a dependency (given that
> this line exists in my rootfileset).  

This will show up as a dependency (a class reference). It should be picked up.

Conor


--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>