Reputation: 63
I'm trying to decompile specific classes from a jar file using the com.strobel.decompiler.Decompiler
decompiler from the Procyon
library.
This is my current approach:
// jar file containing foo.class and bar.class
JarFile myJar = new JarFile("my.jar");
// creating decompiler settings
DecompilerSettings settings = new DecompilerSettings();
// set type loader to jar file
settings.setTypeLoader(new JarTypeLoader(myJar));
StringWriter foo = new StringWriter();
Decompiler.decompile("com.myjar.foo", new PlainTextOutput(foo), settings);
System.out.print(foo.toString());
But this does only print: !!! ERROR: Failed to load class com.myjar.foo.
I'm pretty sure I missed something for class loading the classes from my.jar
. (Thought this would be done by setting the type loader).
The actual question: how do I decompile a specific class from a jar file with the procyon decompiler ? (what i've done wrong in my approach ?)
Greets, NopMind.
Upvotes: 3
Views: 1732
Reputation: 25623
You can coax Procyon into being more forgiving with class names. All you have to do is wrap your 'primary' type loader in an InputTypeLoader
.
settings.setTypeLoader(new InputTypeLoader(new JarTypeLoader(myJar)));
The InputTypeLoader
will first try to locate classes using your primary type loader, and if it can't find a match, it will try to 'massage' the class name. It's used by the command-line decompiler, where users may try to use an alternate form, like .
instead of /
or $
. For example, if there exists a class com/jar/Foo
, and the user tries to decompile com.jar.Foo
, it should be able to resolve that. It should work for inner classes too, e.g., com.jar.Foo.Bar
could be used to locate com/jar/Foo$Bar
. It's up to you whether you want to use this.
I do have a recommendation for you, though: you probably don't want to be using a JarTypeLoader
as your primary type loader. If you do that, Procyon will only search for classes inside your specific jar. That may sound like what you want, but it's probably not.
See, there are some optimizations that Procyon can only perform when it can resolve and analyze a class's dependencies. For example, when it decompiles a method call, Procyon will initially insert casts in front of every argument that doesn't exactly match the parameter types on the target method. It has to do this for correctness, because the method could have overloads, and removing those casts might result in the call being bound the wrong method. However, if Procyon can locate the class that declared the method and it can locate all of its ancestor classes, then it can figure out which casts can be safely removed while still binding to the correct method. It then removes those redundant casts, resulting in cleaner output. That's just one example—there are others too.
Here is what I'd recommend using:
settings.setTypeLoader(
new InputTypeLoader( // allow more relaxed type names
new CompositeTypeLoader(
new JarTypeLoader(myJar), // search your specific jar first
new ClasspathTypeLoader() // fall back to your classpath
)
)
);
This will give Procyon the opportunity search for dependencies in the JRE and anywhere else that happens to be in your classpath.
Upvotes: 0
Reputation: 63
The answer is simple: class namespaces are not prefixed with .
then with /
instead.
So just replacing Decompiler.decompile("com/myjar/foo", ...)
works fine. Sorry
Upvotes: 1