Skip to content

Commit 51b92f0

Browse files
authored
Merge pull request #40 from moacirrf/ft-fernflower
Ft fernflower
2 parents b11fea5 + 5218395 commit 51b92f0

13 files changed

Lines changed: 684 additions & 45 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target/

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
Java Decompiler for Netbeans ![master](https://github.com/moacirrf/nb-java-decompiler/actions/workflows/maven-publish.yml/badge.svg)
22
=====================================
3-
Java Decompiler for Apache Netbeans uses [CFR - another java decompiler](https://www.benf.org/other/cfr/).
3+
Java Decompiler for Apache Netbeans supports two engines: **CFR** and **Fernflower**. A "Decompile" menu contains both options, and the editor popup/toolbar follow suit.
44

55
## Description
6-
This a very simple plugin, with only basic features. If you want to help, contact-me or make a pull-request.
7-
8-
- Apache Netbeans 16,17
9-
- JDK 11+
6+
This is a very simple plugin, with only basic features. The latest release adds Fernflower alongside CFR; you can choose the engine from a submenu.
7+
Contributions are welcome via PRs or issues.
8+
9+
- Apache Netbeans 17+
10+
- JDK 17+
1011

1112
## Licenses
1213
- NB Java Decompiler - GNU General Public License 3.0
13-
- CFR - another java decompiler - MIT license
14+
- CFR – another java decompiler – MIT license
15+
- Fernflower – Apache License 2.0 (source code bundled with plugin)
1416

1517
## Screenshots
1618

nb-configuration.xml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,38 @@ That way multiple projects can share the same settings (useful for formatting ru
1414
Any value defined here will override the pom.xml file value but is only applicable to the current project.
1515
-->
1616
<netbeans.hint.license>gpl30</netbeans.hint.license>
17+
<netbeans.hint.jdkPlatform>JDK_17.0.8.1-tem__SDKMAN_</netbeans.hint.jdkPlatform>
18+
<org-netbeans-modules-javascript2-requirejs.enabled>true</org-netbeans-modules-javascript2-requirejs.enabled>
19+
<org-netbeans-modules-editor-indent.text.x-toml.CodeStyle.project.indent-shift-width>2</org-netbeans-modules-editor-indent.text.x-toml.CodeStyle.project.indent-shift-width>
20+
<org-netbeans-modules-editor-indent.text.x-toml.CodeStyle.project.spaces-per-tab>2</org-netbeans-modules-editor-indent.text.x-toml.CodeStyle.project.spaces-per-tab>
21+
<org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.indent-shift-width>
22+
<org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.tab-size>4</org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.tab-size>
23+
<org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.x-go.CodeStyle.project.expand-tabs>
24+
<org-netbeans-modules-editor-indent.text.x-antlr3.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-antlr3.CodeStyle.project.indent-shift-width>
25+
<org-netbeans-modules-editor-indent.text.x-yaml.CodeStyle.project.indent-shift-width>2</org-netbeans-modules-editor-indent.text.x-yaml.CodeStyle.project.indent-shift-width>
26+
<org-netbeans-modules-editor-indent.text.x-antlr4.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-antlr4.CodeStyle.project.indent-shift-width>
27+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>chars</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-line-wrap>
28+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.indent-shift-width>
29+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaces-per-tab>
30+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enable-indent>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.enable-indent>
31+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>8</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.tab-size>
32+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.text-limit-width>
33+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.expand-tabs>
34+
<org-netbeans-modules-editor-indent.text.html.CodeStyle.project.indent-shift-width>8</org-netbeans-modules-editor-indent.text.html.CodeStyle.project.indent-shift-width>
35+
<org-netbeans-modules-editor-indent.text.html.CodeStyle.project.spaces-per-tab>8</org-netbeans-modules-editor-indent.text.html.CodeStyle.project.spaces-per-tab>
36+
<org-netbeans-modules-editor-indent.text.html.CodeStyle.project.expand-tabs>false</org-netbeans-modules-editor-indent.text.html.CodeStyle.project.expand-tabs>
37+
<org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>chars</org-netbeans-modules-editor-indent.CodeStyle.project.text-line-wrap>
38+
<org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>4</org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width>
39+
<org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>4</org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab>
40+
<org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>8</org-netbeans-modules-editor-indent.CodeStyle.project.tab-size>
41+
<org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>80</org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width>
42+
<org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>true</org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs>
43+
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
44+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>java;javax;org;com;</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.importGroupsOrder>
45+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.countForUsingStarImport>999</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.countForUsingStarImport>
46+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.countForUsingStaticStarImport>999</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.countForUsingStaticStarImport>
47+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStaticStarImport>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStaticStarImport>
48+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStarImport>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.allowConvertToStarImport>
49+
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMemberInsertionPoint>CARET_LOCATION</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classMemberInsertionPoint>
1750
</properties>
1851
</project-shared-configuration>

pom.xml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
<plugin>
8484
<groupId>org.apache.netbeans.utilities</groupId>
8585
<artifactId>nbm-maven-plugin</artifactId>
86-
<version>4.7</version>
86+
<version>14.4</version>
8787
<extensions>true</extensions>
8888
<configuration>
8989
<author>Moacir da Roza Flores-moacirrf@gmail.com</author>
@@ -101,8 +101,8 @@
101101
<artifactId>maven-compiler-plugin</artifactId>
102102
<version>3.8.1</version>
103103
<configuration>
104-
<source>11</source>
105-
<target>11</target>
104+
<source>17</source>
105+
<target>17</target>
106106
</configuration>
107107
</plugin>
108108
<plugin>
@@ -213,14 +213,25 @@
213213
<type>jar</type>
214214
</dependency>
215215

216+
<!-- Fernflower via JitPack -->
217+
<dependency>
218+
<groupId>com.github.jetbrains</groupId>
219+
<artifactId>fernflower</artifactId>
220+
<version>pycharm~252.27397.106</version>
221+
</dependency>
222+
216223
</dependencies>
217224

218225
<repositories>
219226
<repository>
220227
<id>central</id>
221228
<url>https://repo.maven.apache.org/maven2/</url>
222229
</repository>
223-
230+
<!-- JitPack -->
231+
<repository>
232+
<id>jitpack.io</id>
233+
<url>https://jitpack.io</url>
234+
</repository>
224235
</repositories>
225236

226237
<properties>
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package io.github.moacirrf.javadecompiler;
2+
3+
import static com.machinezoo.noexception.Exceptions.wrap;
4+
5+
import static java.util.Objects.nonNull;
6+
7+
import io.github.moacirrf.javadecompiler.files.TempDir;
8+
import io.github.moacirrf.javadecompiler.validator.FileValidator;
9+
10+
import java.awt.event.ActionEvent;
11+
import java.awt.event.ActionListener;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
15+
import org.netbeans.api.java.source.UiUtils;
16+
import org.openide.loaders.DataObject;
17+
import org.openide.awt.ActionID;
18+
import org.openide.awt.ActionReference;
19+
import org.openide.awt.ActionReferences;
20+
import org.openide.awt.ActionRegistration;
21+
import org.openide.filesystems.FileObject;
22+
import org.openide.filesystems.FileUtil;
23+
import org.openide.util.NbBundle.Messages;
24+
25+
@ActionID(
26+
category = "Tools",
27+
id = "io.github.moacirrf.javadecompiler.DecompileCfrAction"
28+
)
29+
@ActionRegistration(
30+
displayName = "#CTL_DecompileWithCFR",
31+
iconInMenu = false
32+
)
33+
@ActionReferences({
34+
@ActionReference(path = "Editors/Popup/Decompile"),
35+
@ActionReference(path = "UI/ToolActions/Decompile", position = 1)
36+
})
37+
@Messages("CTL_DecompileWithCFR=Decompile With CFR")
38+
public final class DecompileCfrAction implements ActionListener {
39+
40+
private static final String DECOMPILER = "cfr";
41+
42+
private final DataObject context;
43+
private final Path decompilerDir;
44+
45+
public DecompileCfrAction(DataObject context) {
46+
this.context = context;
47+
this.decompilerDir = Path.of(TempDir.getTempDir().toString(), DECOMPILER);
48+
wrap(ExceptionHandler::handleException).run(() -> {
49+
if (!Files.exists(decompilerDir)) {
50+
Files.createDirectory(decompilerDir);
51+
}
52+
});
53+
}
54+
55+
@Override
56+
public void actionPerformed(ActionEvent ev) {
57+
FileObject file = context.getPrimaryFile();
58+
if (FileValidator.validate(file)) {
59+
Decompiler<String, FileObject> decompiler = DecompilerFactory.create(DecompilerFactory.DecompilerType.CFR);
60+
writeToNewClass(file, decompiler.decompile(file));
61+
}
62+
}
63+
64+
private void writeToNewClass(FileObject file, String decompiled) {
65+
if (nonNull(decompiled) && !decompiled.isEmpty()) {
66+
wrap(ExceptionHandler::handleException).run(() -> {
67+
Path newFile = Path.of(decompilerDir.toString(), file.getName().concat(".java"));
68+
if (Files.exists(newFile)) {
69+
newFile.toFile().setWritable(true);
70+
Files.delete(newFile);
71+
}
72+
Files.write(newFile, decompiled.getBytes());
73+
newFile.toFile().setReadOnly();
74+
75+
FileObject newFileObject = FileUtil.createData(newFile.toFile());
76+
newFileObject.setAttribute("disable-java-errors", true);
77+
UiUtils.open(newFileObject, 1);
78+
});
79+
}
80+
}
81+
}

src/main/java/io/github/moacirrf/javadecompiler/DecompileAction.java renamed to src/main/java/io/github/moacirrf/javadecompiler/DecompileFernflowerAction.java

Lines changed: 44 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,17 @@
1717
package io.github.moacirrf.javadecompiler;
1818

1919
import static com.machinezoo.noexception.Exceptions.wrap;
20+
2021
import static java.util.Objects.nonNull;
22+
2123
import io.github.moacirrf.javadecompiler.files.TempDir;
2224
import io.github.moacirrf.javadecompiler.validator.FileValidator;
25+
2326
import java.awt.event.ActionEvent;
2427
import java.awt.event.ActionListener;
2528
import java.nio.file.Files;
2629
import java.nio.file.Path;
30+
2731
import org.netbeans.api.java.source.UiUtils;
2832
import org.openide.loaders.DataObject;
2933
import org.openide.awt.ActionID;
@@ -35,51 +39,61 @@
3539
import org.openide.util.NbBundle.Messages;
3640

3741
@ActionID(
38-
category = "Tools",
39-
id = "io.github.moacirrf.javadecompiler.DecompileAction"
42+
category = "Tools",
43+
id = "io.github.moacirrf.javadecompiler.DecompileFernflowerAction"
4044
)
4145
@ActionRegistration(
42-
displayName = "#CTL_DecompileAction"
46+
displayName = "#CTL_DecompileWithFernflower",
47+
iconInMenu = false
4348
)
44-
@ActionReferences(value = {
45-
@ActionReference(path = "Editors/Popup", position = 1425),
46-
@ActionReference(path = "UI/ToolActions", position = 2950)
49+
@ActionReferences({
50+
@ActionReference(path = "Editors/Popup/Decompile"),
51+
@ActionReference(path = "UI/ToolActions/Decompile", position = 2)
52+
})
53+
@Messages({
54+
"CTL_DecompileWithFernflower=Decompile With Fernflower"
4755
})
48-
@Messages("CTL_DecompileAction=Decompile")
49-
public final class DecompileAction implements ActionListener {
56+
public final class DecompileFernflowerAction implements ActionListener {
57+
58+
private static final String DECOMPILER = "fernflower";
5059

5160
private final DataObject context;
5261
private final Path decompilerDir;
5362

54-
public DecompileAction(DataObject context) {
55-
this.context = context;
56-
this.decompilerDir = TempDir.getTempDir();
63+
public DecompileFernflowerAction(DataObject context) {
64+
this.context = context;
65+
this.decompilerDir = Path.of(TempDir.getTempDir().toString(), DECOMPILER);
66+
wrap(ExceptionHandler::handleException).run(() -> {
67+
if (!Files.exists(decompilerDir)) {
68+
Files.createDirectory(decompilerDir);
69+
}
70+
});
5771
}
5872

5973
@Override
6074
public void actionPerformed(ActionEvent ev) {
61-
FileObject file = context.getPrimaryFile();
62-
if (FileValidator.validate(file)) {
63-
Decompiler<String, FileObject> decompiler = DecompilerFactory.create();
64-
writeToNewClass(file, decompiler.decompile(file));
65-
}
75+
FileObject file = context.getPrimaryFile();
76+
if (FileValidator.validate(file)) {
77+
Decompiler<String, FileObject> decompiler = DecompilerFactory.create(DecompilerFactory.DecompilerType.FERNFLOWER);
78+
writeToNewClass(file, decompiler.decompile(file));
79+
}
6680
}
6781

6882
private void writeToNewClass(FileObject file, String decompiled) {
69-
if (nonNull(decompiled) && !decompiled.isEmpty()) {
70-
wrap(ExceptionHandler::handleException).run(() -> {
71-
Path newFile = Path.of(decompilerDir.toString(), file.getName().concat(".java"));
72-
if (Files.exists(newFile)) {
73-
newFile.toFile().setWritable(true);
74-
Files.delete(newFile);
75-
}
76-
Files.write(newFile, decompiled.getBytes());
77-
newFile.toFile().setReadOnly();
83+
if (nonNull(decompiled) && !decompiled.isEmpty()) {
84+
wrap(ExceptionHandler::handleException).run(() -> {
85+
Path newFile = Path.of(decompilerDir.toString(), file.getName().concat(".java"));
86+
if (Files.exists(newFile)) {
87+
newFile.toFile().setWritable(true);
88+
Files.delete(newFile);
89+
}
90+
Files.write(newFile, decompiled.getBytes());
91+
newFile.toFile().setReadOnly();
7892

79-
FileObject newFileObject = FileUtil.createData(newFile.toFile());
80-
newFileObject.setAttribute("disable-java-errors", true);
81-
UiUtils.open(newFileObject, 1);
82-
});
83-
}
93+
FileObject newFileObject = FileUtil.createData(newFile.toFile());
94+
newFileObject.setAttribute("disable-java-errors", true);
95+
UiUtils.open(newFileObject, 1);
96+
});
97+
}
8498
}
8599
}

src/main/java/io/github/moacirrf/javadecompiler/DecompilerFactory.java

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,53 @@
1616
*/
1717
package io.github.moacirrf.javadecompiler;
1818

19-
import io.github.moacirrf.javadecompiler.cfr.DecompilerClassImpl;
20-
2119
/**
2220
*
2321
* @author Moacir da Roza Flores <moacirrf@gmail.com>
2422
*/
2523
public final class DecompilerFactory {
2624

25+
public enum DecompilerType {
26+
CFR,
27+
FERNFLOWER
28+
}
29+
30+
private static DecompilerType defaultType = DecompilerType.CFR;
31+
32+
/**
33+
* Create a decompiler using the default type (CFR)
34+
* @return Decompiler instance
35+
*/
2736
public static Decompiler create() {
28-
return new DecompilerClassImpl();
37+
return create(defaultType);
38+
}
39+
40+
/**
41+
* Create a decompiler of the specified type
42+
* @param type The type of decompiler to create
43+
* @return Decompiler instance
44+
*/
45+
public static Decompiler create(DecompilerType type) {
46+
if (type == DecompilerType.FERNFLOWER) {
47+
return new io.github.moacirrf.javadecompiler.fernflower.DecompilerClassImpl();
48+
}
49+
return new io.github.moacirrf.javadecompiler.cfr.DecompilerClassImpl();
50+
}
51+
52+
/**
53+
* Set the default decompiler type to use
54+
* @param type The default type
55+
*/
56+
public static void setDefaultType(DecompilerType type) {
57+
defaultType = type;
58+
}
59+
60+
/**
61+
* Get the current default decompiler type
62+
* @return The default type
63+
*/
64+
public static DecompilerType getDefaultType() {
65+
return defaultType;
2966
}
3067

3168
private DecompilerFactory() {

0 commit comments

Comments
 (0)