Java class parser - java

I am parsing all the class files in a jar via Objectweb asm (http://forge.ow2.org/projects/asm/). The idea is to parse and store (and use for something later) all the public/protected methods and fields in each class file. It is working as expected. What I dont get is the list of methods, declared by the interface and those inherited from superclasses and superinterfaces. Is there a smart parser available that would give me the above list?
I could load the class file and then use java.lang.Class object to get what I need. But loading classes might fail because of dependencies. I would rather parse and get that info.

The data you want is simply not there. Inherited members are implicit: you only have the names of the class and interfaces where they can be looked for, and you need to parse the corresponding class files.

You can simply do this :
Class superclass = aClass.getSuperclass();
aClass.getClass().getInterfaces();
aClass.getClass().getMethods();

Related

How to us a custom ClassLoader to get different and new objects from a library in Java

I want to get new instances of classes that exist inside a library. The library has different classes inherited from one parent class, and I need to get new instances of the child classes. I can provide precisely the class name as a text.
More specifically, I need to create objects of different HL7-v2 messages types from the hapi-base library. It has AbstractMessage class as the parent, while its child classes are ADT_A01, ADT_A02,... etc. I need to create ADT_A01(), ADT_A02()...etc objects from it.
How can I achieve this by using a Class Loader? If not, why?
You don't need to use class loader. You need to use Factory pattern. You need to create a Factory class that has a method get instance that returns the interface or abstract parent class and receives a parameter such as concrete class name or other identifier and the method will return the concrete class. That's a Factory pattern description in a nutshell. Here is just one link about the pattern: Factory method design pattern in Java, there are many more.
Also, I wrote a feature that I called Self-populating factory. you might be interested in using something like this. Here is the article about the feature: https://dzone.com/articles/non-intrusive-access-to-quotorphanedquot-beans-in. This feature (and some other interesting ones) is available in Open source java library called MgntUtils which is written and maintained by me. You can get it as Maven artifacts or on Github (including source code and Javadoc). And Here is a link to the library Javadoc
Class hl7MessageClass = getClass().getClassLoader().loadClass("package_name"+hl7MessageType);
return (AbstractMessage) hl7MessageClas.newInstance();

Loading a compiled class in Java and deserializing it's instance from a file

I need to have an app that during run-time can load another class and deserialize one of it's instance successfuly so that it can run it's methods and read the member variables.
From what I noticed, you can not serialize methods in Java, so I'm thinking about serializing the class instance in project2, load the compiled class with ClassLoader in project1, instantiate it and assign the deserialized instance from porject2 in project1 to the instantiated loaded class.
The serialized class will inherit the same parent class in both projects.
Is this the best way to go? It's a school project so the requirements are that my app can accept any other type of class without changing the code.
TL;DR: My plan is to load a compiled class with the ClassLoader so that my project knows about that class (specifically the methods inside) and then load that serialized class instance inside the project so that I can get the data from the instance and together with the loaded class (now I know the methods aswell), run the methods on the deserialized instance.
You are mistaken. The ability to call a method on some object isn't related to serialization at all.
What I mean: the method implementation is not part of the serialized data! Java serialization only writes field data into that output stream.
The implementation of a method only depends on the class file of some Java class. You can serialize and deserialize your objects as often as you want to - but what happens when you call a method on such an object is only determined by the class file that the corresponding class loader loaded for you when first accessing the corresponding class.
If your goal is really just about "one class dumps an object into a binary representation"; and another piece of code loads that binary data; turns it into an object; to access that object; then you do not need two projects. You also do not need to worry about "the methods being" there. As long as your ClassLoader knows the class of objects to be de-serialized, everything will just work. Just pick an example tutorial, like this here and work through it.
But: when your requirement is to invoke methods or access fields of arbitrary objects; then you don't look into serialization, but into Java reflection.
But a word of warning there: reflections sounds easy, but be assured: there are many many ways for you to write slightly wrong code. And because reflection is basically a runtime thing, the java compiler doesn't help much. You write code that looks reasonable, it compiles, you run it, and you get exceptions throw at you.
In that sense, reflection is an advanced topic in the Java curriculum; and I think you should rather step back and clarify with your teachers what exactly they expect from you.
Given your latest updates: then simply look into that tutorial about serialization (and forget about the reflection part). And to answer your question: yes, that sounds like a viable approach. Can't say more; as you are not sharing code so far.

Different behaviour of Class literal and Class.forName for package local classes

Only for example lets consider the class ClassFileAssembler from the sun.reflect package.
This class is a package local class:
class ClassFileAssembler implements sun.reflect.ClassFileConstants {...
So we can not use even its name ClassFileAssembler, we can not import it directly - it will lead to a compiler error.
However we can create a package named sun.reflect in our project and use the ClassFileAssembler name internally in this package - Java compiler will think that we are inside the ClassFileAssembler's package.
If so, why not to try to get a reference to a class object, i.e. ClassFileAssembler.class?
Class<ClassFileAssembler> classFileAssemblerClass = ClassFileAssembler.class;
Unexpectedly this code leads to a run-time error: java.lang.IllegalAccessError: tried to access class sun.reflect.ClassFileAssembler from class sun.reflect.Test.
However we still able to get the ClassFileAssembler class object:
Class<ClassFileAssembler> aClass = (Class<ClassFileAssembler>)Class.forName("sun.reflect.ClassFileAssembler");
It works fine and gives us a full class description.
So, the questions are:
1) What is the difference between techniques, how Class.forName0 retrieves reference to class object, and how .class does it?
2) Why do they have such different security checks?
3) What's the reason to protect .class reference in such way?
4) Do these techniques use different class loaders?
Class.forName don't care about whether a class is package local or not. It is when you attempt to use that class that access is checked. BTW if you do setAccessible(true) you can by pass these access restrictions.
The Reflection library allows you to do many things you cannot do in Java code. The Java has rules as to what you can and cannot do. e.g. you cannot set a final field outside a constructor or more than once. Note: the JVM doesn't have this restriction and at runtime you can use reflections to change it.
The reason this class is package local is to restrict access of the class to code outside this package. This doesn't mean you cannot access it if you really try, but it is less likely you will access it without serious thought being put into it. e.g. when I import classes in my IDE it often suggests classes from com.sun.* which are unlikely to be the right choice. (MY IDE can be set up to ignore these, but I often seem for find some new package I don't want)
The reason Reflections can do this is to support functionality such a Serialization. With Serialization you need to be able to serialize class outside the package of the Serialization library and obtain fields and reset them when deserializing. Reflections is also used by many Inversion of Control libraries though I suspect this is not what they had in mind when they design it.
If you check the javadoc of Class#forName, you will see that:
Note that this method does not check whether the requested class is accessible to its caller.
there is no difference. but you cannot access the static field .class of the package private (no modifier) class ClassFileAssembler.
everyone could access the Class instances, but the fields are protected.
in fact no one designed to protect .class reference this way, it's side effect of protecting other fields.
i dont think so.

How to programmatically know who (other java files/classes) is using my java class?

I want to get a list of all java class which are dependent on my class. Is there a library which exposes intended API? API is expected to return list of java classes using my java class.
You would probably use Reflection API..
They were specifically made for this kind of problems.. They allow to get information about classes at runtime..
You can get: -
All the methods
All the derived classes
All the variables.
And many more information..
You can see Class.getClasses() and Class.getDeclaredClasses()
See some more examples
Reflection can tell you whether a specific class extends your class, uses your class as a field, takes your class as a parameter, or returns your class from a method. However if the use of your class is method confined then reflection will not work.

Is there a way to get the list of InnerClasses through Reflection in Java?

Is there a way to know the inner classes that a Class has through Reflection in Java?
Yes, use Class#getDeclaredClasses() for this. You only need to determine if it's an inner class or a nested (static) class by checking its modifiers. Assuming that Parent is the parent class, here's a kickoff example:
for (Class<?> cls : Parent.class.getDeclaredClasses()) {
if (!Modifier.isStatic(cls.getModifiers())) {
// This is an inner class. Do your thing here.
} else {
// This is a nested class. Not sure if you're interested in this.
}
}
Note: this only doesn't cover anonymous classes, but seeing your previous question on the subject, I don't think you're explicitly asking for them.
No, unfortunately, for the same reason why you cannot enumerate regular classes in a package.
Inner classes are really just ordinary classes at runtime. The compiler does some tweaking to get around the usual access rules, For example, the inner class appears to be able to access private fields and methods of the enclosing class - it can do this because the compiler creates a non-private accessor function that is used by the inner class. See Java in a Nutshell - how inner classes work for details.
Inner classes are regular classes, and these can't be reliably enumerated, so the general answer is no, not possible.
However, it can be solved in specific cases. If you know the JARs you are using, then you can iterate across all files in the JAR, looking for files of the pattern yourpakage.YourClass$<something>.class where <something> is one or more characters.
EDIT:
There are various types of inner class:
declared members, such as interfaces and classes
Anonymous classes and local classes
If you only care about the first case, then BalusC's answer using getDeclaredClasses is the correct one. If you want all inner classes, then getDeclaredClasses unfortunately won't work. See SDN Bug 4191731. In that case, you might try one of the class enumeation methods proposed in the link (such as scanning the JAR file.)
Yes, there is a trick to do that. See an old post about locating resources. Knowing your class(let's say com.domain.api.ClassA), extract the package name, convert the package to a path(replace '.' with '/' and you get com/domain/api) scan for all the files with extension .class in that folder and retain only those files which starts with your class name(ClassA$xxxxx), those are the inner classes for class ClassA

Categories