I have a third-party jar file that comes with the javadocs for only part of the API. Is there a way to reverse engineer the jar file to obtain a complete listing of classes and methods?
jar tf will list the contents for you. javap will allow you to see more details of the classes (see the tools guide).
For instance if you have a class named mypkg.HelloWorld in a jar myjar.jar then run it like
javap -classpath myjar.jar mypkg.HelloWorld
However, are you sure you want to be using these unpublished APIs? It's usually a really bad idea.
As Scott said, you can use Eclipse to get a lot of what you're looking for.
I would recommend getting the JadClipse plugin which will decompile the .class files on the fly and show you actual Java code as you browse the classes in the IDE.
If you're using eclipse, you can just add it to a project's classpath and explore it using the treeview and/or content assist.
I'd assume other IDEs can do similar.
From a command-line point of view, you can unjar it (jar xf foo.jar) and use javap against all files.
Eclipse would work great
A Java Decompiler would translate the classes back into some semblence of source code that you could study to learn about the classes, the methods, their signatures, and maybe even some insight into valid values for some arguments (e.g. don't pass a null for this argument or you'll trigger a NullPointerException immediately). But roll up your sleeves to unjar the jar and run the decompiler against all the class files. This is essentially what Eclipse is doing for help text with undocumented classes.
Finally, of course, a "real programmer" would read the byte-code directly without need for a decompiler.
You can use the library WALA to read out all methods signatures. You'll however need to load Stub-Code for Java first. The following program should read out all the signatures:
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.types.ClassLoaderReference;
import java.util.jar.JarFile;
import java.io.IOException;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
public class methods {
public static void main(String[] args) throws IOException, ClassHierarchyException {
AnalysisScope scope = AnalysisScope.createJavaAnalysisScope();
scope.addToScope(ClassLoaderReference.Primordial, new JarFile("jSDG-stubs-jre1.5.jar"));
scope.addToScope(ClassLoaderReference.Application, new JarFile("myProgram.jar"));
IClassHierarchy cha = ClassHierarchy.make(scope);
for (IClass cl : cha) {
if (cl.getClassLoader().getReference().equals(ClassLoaderReference.Application)) {
for (IMethod m : cl.getAllMethods()) {
String ac = "";
if (m.isAbstract()) ac = ac + "abstract ";
if (m.isClinit()) ac = ac + "clinit ";
if (m.isFinal()) ac = ac + "final ";
if (m.isInit()) ac = ac + "init ";
if (m.isNative()) ac = ac + "native ";
if (m.isPrivate()) ac = ac + "private ";
if (m.isProtected()) ac = ac + "protected ";
if (m.isPublic()) ac = ac + "public ";
if (m.isSynchronized()) ac = ac + "synchronized ";
System.out.println(ac + m.getSignature());
}
}
}
}
}
If you use the adapted WALA-version from here it does Dalvik (e.g. Android Apps) as well.
a quick help for knowing methods of a normal class (not abstract class),I do the following .
new classname().press ctrl+space for methods listing in eclipse.
Use Eclipse > Package Explorer to see the classes and thier hierarchy.
Content Assist(autocomplete feature (ctrl + space)) is also a good help , but wouldnt recomend using an unpublished API
Related
I want to use Soot library to build an SSA from *.java file. But all the examples I found use Soot as standalone tool, not library. Can anyone give me example hot to do it in program?
For a start I am just trying to load my class from the source file and print it (TestClass.class is in the directory A/home/abdullin/workspace/test):
import soot.G
import soot.Scene
import soot.options.Options
fun main(args: Array<String>) {
G.reset();
Options.v().set_whole_program(true)
Scene.v().loadBasicClasses()
Scene.v().sootClassPath = "${Scene.v().defaultClassPath()}:/home/abdullin/workspace/test"
val sc = Scene.v().getSootClass("TestClass")
Scene.v().loadNecessaryClasses()
sc.setApplicationClass()
println(sc.name)
sc.methods.forEach {
println(it)
}
}
But when I run this, I get runtime exception Aborting: can't find classfile TestClass. If I change Scene.v().getSootClass("TestClass") to Scene.v().loadClassAndSupport("TestClass") as they do in some of their tutorials, soot finds my class, but it is not complete. It prints me signatures of class methods, but can't find their bodies, activeBody field is null.
TestClass
<TestClass: void <init>()>
<TestClass: void main(java.lang.String[])>
<TestClass: void f1()>
First, make sure that the Soot jar is in the classpath.
Then, set up Soot using the classes soot.G and soot.options.Options (G.reset() and Options.v().parse() are methods of interest, also see command line options).
Using soot.Scene.v().setSootClassPath() and similar you can tell Soot where to find the class files of the code you want to analyze.
You can then use Scene.v().getSootClass() to obtain SootClass objects. Make sure that Soot loads all classes after setting the class you want to analyze as main class:
mySootClass.setApplicationClass();
Scene.v().loadNecessaryClasses();
After this, you can use Soot to obtain various types of graphs and run you analyses, as described in the Survivor's guide
You can read this post (https://o2lab.github.io/710/p/a1.html). But if you try to analyze a jar file, you should unzip it and get a set of class files. Then you should add your classes directory into the soot_class_path.
Demo:
public static void main(String[] args) {
//spotbugs -- testing
String classesDir = "D:\\wkspace\\seed8\\dir\\spotbugs";
String mainClass = "edu.umd.cs.findbugs.LaunchAppropriateUI";
//set classpath
String jreDir = System.getProperty("java.home") + "\\lib\\jce.jar";
String jceDir = System.getProperty("java.home") + "\\lib\\rt.jar";
String path = jreDir + File.pathSeparator + jceDir + File.pathSeparator + classesDir;
Scene.v().setSootClassPath(path);
//add an intra-procedural analysis phase to Soot
TestCallGraphSootJar_3 analysis = new TestCallGraphSootJar_3();
PackManager.v().getPack("wjtp").add(new Transform("wjtp.TestSootCallGraph", analysis));
excludeJDKLibrary();
Options.v().set_process_dir(Arrays.asList(classesDir));
Options.v().set_whole_program(true);
//Options.v().set_app(true);
SootClass appClass = Scene.v().loadClassAndSupport(mainClass);
Scene.v().setMainClass(appClass);
Scene.v().loadNecessaryClasses();
//enableCHACallGraph();
enableSparkCallGraph();
PackManager.v().runPacks();
}
If you replace
SootClass appclass = Scene.v().loadClassAndSupport(mainclass);
Scene.v().setMainClass(appclass);
Scene.v().loadNecessaryClasses();
by
Scene.v().loadNecessaryClasses();
SootClass appclass = Scene.v().getSootClass(mainclass);
Scene.v().setMainClass(appclass);
, the program also works.
I use the class javax.tools.JavaCompiler (jdk6) to compile a source file, but the source file depends on some jar file. How to set the classpath of the javax.tools.JavaCompiler?
The javax.tools.JavaCompiler#getTask() method takes an options parameter that allows to set compiler options. The following message describes an easy way to set them in order to access the calling program's classpath:
You need to configure the standard
java file manager to know about the
jar files(s) - you use the compiler
options argument to do that.
By default the java compiler object
only seems to know about the default
locations for bootclasspath, extdirs
and endorseddirs directories in terms
of its classpath.
You need to add the calling program's
current classpath to the java compiler
instance's which gets passed on the
the standard file manager, which will
then find classes in the jar files.
Here's how I do it in the compiler
wrapper I wrote
List<String> optionList = new ArrayList<String>();
// set compiler's classpath to be same as the runtime's
optionList.addAll(Arrays.asList("-classpath",System.getProperty("java.class.path")));
// any other options you want
optionList.addAll(Arrays.asList(options));
JavaCompiler.CompilationTask task = compiler.getTask(out,jfm,diagnostics,optionList,null,jfos);
All you'll need then is to get the proper classpath set when running the calling program.
The same problem occurred to me recently, finally I found two workarounds. You can set the class path either by invoke StandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, "YOUR_CLASS_PATH") or Compiler.getTask(ARG_0, ARG_1, ARG_2, CLASS_PATH_OPTIONS, just as the first answer posted here says.
I needed something simpler than the examples above.
The following is a self-contained example of using the built-in Java compiler, and setting the classpath for the compiler to use.
It is equivalent to creating a source file called HelloPrinter.java and then compiling it as follows:
javac -classpath C:\Users\dab\Testing\a.jar;c:\path\etc org\abc\another\HelloPrinter.java
Note how the classpath can be set using a String[] of options. This should be familiar if you're already used to running javac on the command line (as above).
This code is compatible with Java 6. You will need a JDK, not a JRE, for this to run. This example doesn't actually use the classpath. It all does is print "Hello". You can add an import statement to the generated source and call a method in an external Jar file to test this properly.
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class JavaCompilerExample {
public static void main(String[] args) throws Exception {
String className = "HelloPrinter";
String directoryName = "org/abc/another";
new File(directoryName).mkdirs();
FileOutputStream fos = new FileOutputStream(directoryName+"/"+className+".java");
PrintStream ps = new PrintStream(fos);
ps.println(
"package "+directoryName.replace("/", ".") + " ; "
+ "public class " +className +
"{ public static void main(String[] args){System.out.println(\"Hello\");} }");
ps.close();
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
String javacOpts[] = {"-classpath",
"C:\\Users\\dab\\Testing\\a.jar;c:\\path\\etc;",
directoryName+"/"+className + ".java"};
if ( javac.run(null, null, null, javacOpts)!=0 ) {
System.err.println("Error");
System.exit(1);
}
}
}
how to find the name of jar which contains the specific class through ant script?
We are using the following Ant code to find the jar containing our main class. It requires Ant 1.8+.
<whichresource class="${main.class}" property="main.class.url">
<classpath>
<fileset dir="${jar.dir}" includes="*.jar" />
</classpath>
</whichresource>
<pathconvert property="jar.file">
<url url="${main.class.url}" />
<regexpmapper from="jar:file:/(.*)!.*" to="\1" />
</pathconvert>
<echo>Jar file containing main class: ${jar.file}</echo>
I hope this answers your question.
Maarten
Try jarscan . It is a commandline java tool, it should be easy if you want to integrate it through ant also.
I think this problem can be better solved by a 1-line (ok, 5-line) C-shell script. Suppose you are trying to find a list of jar files in some directory that contain a certain file. Try this at your csh prompt:
% cd directory_where_your_jar_files_reside
% set f2Search = filename_you_are_looking_for
% foreach jarFile (*.jar)
? (jar tvf $jarFile | grep $f2Search > /dev/null) || echo $jarFile
? end
You can obviously concat the output to some other file if required. This is a Unix solution, dunno how to do this on Windows, sorry. Apologies for not answering the Ant question, but others have answered it already. Hope this helps, - M.S.
That's not really what Ant is for.
Ant is primarily a build tool, and it's core functionalities revolve around that. Yes, it can be used for additional functions, but it's still best to use it what it was intended for. Finding a class inside a JAR file isn't what it's good at.
You may be better off just doing this in Java. Java offers functionality to open up JAR files and inspect the contents. You can use those to find the class you are looking for. Or, use another tool that's intended to do that, such as the Jarscan that Biju mentions.
I agree with rfeak this is not what ANT is designed for. Having said that, it can very be a frustrating to determine how to resolve missing class dependencies.....
I use the findjar website. It indexes most of the available open source libraries.
If you really need to do this, one approach that might work is to loop through all the JAR files and pass each one to the available task as the lone classpath path element. The class you're interested in would be used for the classname attribute.
Edit: Since it sounds like you're now entertaining non-Ant solutions, here's a variation of the find-my-class code:
import java.net.URL;
public class ClassFinder {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c = Class.forName(args[0]);
URL url = c.getResource(c.getSimpleName() + ".class");
System.out.println("location of " + args[0] + ": " + url);
}
}
With Java 6, you can use classpath wildcards (see "Understanding class path wildcards"), so it should be easy to include your directory of JARs and see how fast it is.
Edit2: And if you want to find multiple locations...
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
public class ClassFinder {
public static void main(String[] args) throws IOException {
String classResourceName = args[0].replaceAll("\\.", "/") + ".class";
ClassLoader loader = ClassFinder.class.getClassLoader();
Enumeration<URL> classResources = (loader == null) ? ClassLoader.getSystemResources(classResourceName) : loader.getResources(classResourceName);
if (classResources.hasMoreElements()) {
System.out.println("Locations of " + args[0] + ":");
while (classResources.hasMoreElements()) {
URL url = classResources.nextElement();
URLConnection conn = url.openConnection();
String loc = (conn instanceof JarURLConnection) ? ((JarURLConnection)conn).getJarFile().getName() : url.toString();
System.out.println(loc);
}
} else {
System.out.println("No locations found for " + args[0]);
}
}
}
I want to import a class that I made in my project, into my script
I did this but it doesn't work:
function doFunction(){
//Objectif Mensuel
importPackage(java.lang);
importClass(KPDataModel.KPData.KPItem); //ERROR HERE, this is my class that I want to import
KPItem kpItem = kpItemList.get(0);
System.out.println(kpItem.CellList.get(2).Value);
System.out.println("-------");
var proposedMediationSum = Integer.parseInt(kpItemList.get(0).CellList.get(2).Value);
var refusedMediationSum = Integer.parseInt(kpItemList.get(0).CellList.get(3).Value)
var totalMediation = proposedMediationSum + refusedMediationSum;
kpItemList.get(0).CellList.get(4).Value = totalMediation;
}
Well, thnx a lot, I found that the problem comes from the import.
This is what it said in the Oracle website :
The Packages global variable can be
used to access Java packages.
Examples: Packages.java.util.Vector,
Packages.javax.swing.JFrame. Please
note that "java" is a shortcut for
"Packages.java". There are equivalent
shortcuts for javax, org, edu, com,
net prefixes, so pratically all JDK
platform classes can be accessed
without the "Packages" prefix.
So, to import my class I used : importClass(Packages.KPDataModel.KPData.KPItem);
I use the class javax.tools.JavaCompiler (jdk6) to compile a source file, but the source file depends on some jar file. How to set the classpath of the javax.tools.JavaCompiler?
The javax.tools.JavaCompiler#getTask() method takes an options parameter that allows to set compiler options. The following message describes an easy way to set them in order to access the calling program's classpath:
You need to configure the standard
java file manager to know about the
jar files(s) - you use the compiler
options argument to do that.
By default the java compiler object
only seems to know about the default
locations for bootclasspath, extdirs
and endorseddirs directories in terms
of its classpath.
You need to add the calling program's
current classpath to the java compiler
instance's which gets passed on the
the standard file manager, which will
then find classes in the jar files.
Here's how I do it in the compiler
wrapper I wrote
List<String> optionList = new ArrayList<String>();
// set compiler's classpath to be same as the runtime's
optionList.addAll(Arrays.asList("-classpath",System.getProperty("java.class.path")));
// any other options you want
optionList.addAll(Arrays.asList(options));
JavaCompiler.CompilationTask task = compiler.getTask(out,jfm,diagnostics,optionList,null,jfos);
All you'll need then is to get the proper classpath set when running the calling program.
The same problem occurred to me recently, finally I found two workarounds. You can set the class path either by invoke StandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, "YOUR_CLASS_PATH") or Compiler.getTask(ARG_0, ARG_1, ARG_2, CLASS_PATH_OPTIONS, just as the first answer posted here says.
I needed something simpler than the examples above.
The following is a self-contained example of using the built-in Java compiler, and setting the classpath for the compiler to use.
It is equivalent to creating a source file called HelloPrinter.java and then compiling it as follows:
javac -classpath C:\Users\dab\Testing\a.jar;c:\path\etc org\abc\another\HelloPrinter.java
Note how the classpath can be set using a String[] of options. This should be familiar if you're already used to running javac on the command line (as above).
This code is compatible with Java 6. You will need a JDK, not a JRE, for this to run. This example doesn't actually use the classpath. It all does is print "Hello". You can add an import statement to the generated source and call a method in an external Jar file to test this properly.
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
public class JavaCompilerExample {
public static void main(String[] args) throws Exception {
String className = "HelloPrinter";
String directoryName = "org/abc/another";
new File(directoryName).mkdirs();
FileOutputStream fos = new FileOutputStream(directoryName+"/"+className+".java");
PrintStream ps = new PrintStream(fos);
ps.println(
"package "+directoryName.replace("/", ".") + " ; "
+ "public class " +className +
"{ public static void main(String[] args){System.out.println(\"Hello\");} }");
ps.close();
JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
String javacOpts[] = {"-classpath",
"C:\\Users\\dab\\Testing\\a.jar;c:\\path\\etc;",
directoryName+"/"+className + ".java"};
if ( javac.run(null, null, null, javacOpts)!=0 ) {
System.err.println("Error");
System.exit(1);
}
}
}