Skip to content

Commit

Permalink
Fix loading of embedded/inner/annonymous classes
Browse files Browse the repository at this point in the history
  • Loading branch information
kwart committed Jan 7, 2020
1 parent 21354d8 commit 782105a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void decompile(JavaDecompiler javaDecompiler, JDOutput jdOutput) {
final String name = file.getName();
LOGGER.debug("Decompiling single class file {}", name);
String nameWithoutClassSfx = IOUtils.isClassFile(name) ? IOUtils.cutClassSuffix(name) : name;
jdOutput.processClass(nameWithoutClassSfx, javaDecompiler.decompileClass(FileLoader.INSTANCE, file.getPath()));
jdOutput.processClass(nameWithoutClassSfx, javaDecompiler.decompileClass(new FileLoader(), file.getPath()));
jdOutput.commit();
}
}
7 changes: 4 additions & 3 deletions jd-lib/src/main/java/com/github/kwart/jd/input/DirInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@
public class DirInput extends AbstractFileJDInput {

private static final Logger LOGGER = LoggerFactory.getLogger(DirInput.class);
private final FileLoader fileLoader;

public DirInput(String path) {
super(path);
if (!file.isDirectory()) {
throw new IllegalArgumentException("Path doesn't denote a directory.");
}

this.fileLoader = new FileLoader(path);
}

@Override
Expand Down Expand Up @@ -76,8 +77,8 @@ private void processFile(JavaDecompiler javaDecompiler, JDOutput jdOutput, Strin
return;
}
LOGGER.debug("Decompiling {}", nextFile);
jdOutput.processClass(IOUtils.cutClassSuffix(nameWithPath),
javaDecompiler.decompileClass(FileLoader.INSTANCE, nextFile.getAbsolutePath()));
String internalName = IOUtils.cutClassSuffix(nameWithPath);
jdOutput.processClass(internalName, javaDecompiler.decompileClass(fileLoader, internalName));
} else if (!javaDecompiler.getOptions().isSkipResources()) {
LOGGER.debug("Processing resource file {}", nextFile);
FileInputStream fis = null;
Expand Down
42 changes: 35 additions & 7 deletions jd-lib/src/main/java/com/github/kwart/jd/loader/FileLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.jd.core.v1.api.loader.Loader;
Expand All @@ -12,25 +13,52 @@
*/
public final class FileLoader implements Loader {

/**
* Singleton instance.
*/
public static final FileLoader INSTANCE = new FileLoader();
private final String basePath;

private FileLoader() {
public FileLoader() {
this(null);
}

public FileLoader(String basePath) {
this.basePath = basePath;
}

@Override
public byte[] load(String internalName) throws LoaderException {
try {
return Files.readAllBytes(Paths.get(internalName));
return Files.readAllBytes(fixPath(internalName));
} catch (IOException e) {
throw new LoaderException(e);
}
}

@Override
public boolean canLoad(String internalName) {
return Files.isReadable(Paths.get(internalName));
Path fixedPath = fixPath(internalName);
return fixedPath != null;
}

public Path fixPath(String internalName) {
Path path = Paths.get(internalName);
if (Files.isReadable(path)) {
return path;
}
if (basePath != null) {
path = Paths.get(basePath, internalName);
if (Files.isReadable(path)) {
return path;
}
}
path = Paths.get(internalName + ".class");
if (Files.isReadable(path)) {
return path;
}
if (basePath != null) {
path = Paths.get(basePath, internalName + ".class");
if (Files.isReadable(path)) {
return path;
}
}
return null;
}
}
23 changes: 23 additions & 0 deletions jd-lib/src/test/java/com/github/kwart/jd/HelloWorld.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,34 @@
*/
public final class HelloWorld {

private final PrivateClass priv;

private HelloWorld() {
System.out.println("ctor");
priv = new PrivateClass();
priv.test();
}

public static void main(String[] args) {
System.out.println("xxx");
StaticClass.test();
}

/**
* Static test class.
*/
public static class StaticClass {
public static String test() {
return "static";
}
}

/**
* Private test class.
*/
private class PrivateClass {
public String test() {
return "private";
}
}
}
52 changes: 35 additions & 17 deletions jd-lib/src/test/java/com/github/kwart/jd/JavaDecompilerTest.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
package com.github.kwart.jd;

import static com.github.kwart.jd.JavaDecompilerConstants.CLASS_SUFFIX;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import org.jd.core.v1.api.loader.Loader;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;

import org.jd.core.v1.api.loader.LoaderException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.github.kwart.jd.loader.ByteArrayLoader;
import com.github.kwart.jd.input.DirInput;
import com.github.kwart.jd.input.JDInput;
import com.github.kwart.jd.options.DecompilerOptions;
import com.github.kwart.jd.output.DirOutput;
import com.github.kwart.jd.output.JDOutput;

/**
* Basic test for {@link JavaDecompiler} class.
*/
public class JavaDecompilerTest {

@Test
public void test() throws LoaderException {

Class<HelloWorld> clazz = HelloWorld.class;
String internalName = clazz.getName();
/**
* Temporary folder.
*/
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();

Loader loader = new ByteArrayLoader(clazz.getResourceAsStream("/" + internalName.replace('.', '/') + CLASS_SUFFIX),
internalName);
String decompiled = new JavaDecompiler(new DecompilerOptions() {
@Test
public void test() throws LoaderException, IOException {
JDInput input = new DirInput("target/test-classes");
File tmpFolder = temporaryFolder.getRoot();
JDOutput output = new DirOutput(tmpFolder.getAbsoluteFile());
JavaDecompiler decompiler = new JavaDecompiler(new DecompilerOptions() {

@Override
public boolean isSkipResources() {
Expand All @@ -39,12 +51,18 @@ public boolean isEscapeUnicodeCharacters() {
public boolean isDisplayLineNumbers() {
return false;
}
}).decompileClass(loader, internalName);
System.out.println(decompiled);
assertTrue(decompiled.contains("public final class HelloWorld {"));
assertTrue(decompiled.contains("public static void main(String[] args)"));
assertTrue(decompiled.contains("System.out.println(\"xxx\");"));
assertTrue(decompiled.contains("private HelloWorld() {"));
});
input.decompile(decompiler, output);
File decompiledFile = new File(tmpFolder, "com/github/kwart/jd/HelloWorld.java");
assertTrue(decompiledFile.isFile());
String decompiled = new String(Files.readAllBytes(decompiledFile.toPath()));
assertThat(decompiled, containsString("public final class HelloWorld {"));
assertThat(decompiled, containsString("public static void main(String[] args)"));
assertThat(decompiled, containsString("System.out.println(\"xxx\");"));
assertThat(decompiled, containsString("private HelloWorld() {"));

assertThat(decompiled, containsString("public static class StaticClass {"));
assertThat(decompiled, containsString("private class PrivateClass {"));
}

}

0 comments on commit 782105a

Please sign in to comment.