Codebase list jd-gui / fbc5b14
Add Java 9+ module support emmanue1 4 years ago
14 changed file(s) with 367 addition(s) and 101 deletion(s). Raw diff Collapse all Expand all
4242 }
4343
4444 protected TreeNodeFactory get(String containerType, Container.Entry entry) {
45 String path = entry.getPath();;
45 String path = entry.getPath();
4646 String type = entry.isDirectory() ? "dir" : "file";
4747 String prefix = containerType + ':' + type + ':';
4848 TreeNodeFactory factory = null;
2525 if (rootPath.toUri().toString().toLowerCase().endsWith(".jmod!/")) {
2626 return true;
2727 } else {
28 // Extension: accept uncompressed WAR file containing a folder 'WEB-INF'
28 // Extension: accept uncompressed JMOD file containing a folder 'classes'
2929 try {
3030 return rootPath.getFileSystem().provider().getScheme().equals("file") && Files.exists(rootPath.resolve("classes"));
3131 } catch (InvalidPathException e) {
4343 TreeNodeFactory treeNodeFactory = api.getTreeNodeFactory(parentEntry);
4444 Object data = (treeNodeFactory != null) ? treeNodeFactory.make(api, parentEntry).getUserObject() : null;
4545 Icon icon = (data instanceof TreeNodeData) ? ((TreeNodeData)data).getIcon() : null;
46 String location = file.getPath();
4647
47 api.addPanel(file.getName(), icon, "Location: " + file.getAbsolutePath(), mainPanel);
48 api.addPanel(file.getName(), icon, "Location: " + location, mainPanel);
4849 return mainPanel;
4950 }
5051 }
121121
122122 protected void enterTypeDeclaration(ParserRuleContext ctx) {
123123 // Add type declaration
124 String typeName = ctx.getToken(JavaParser.Identifier, 0).getText();
125 int length = sbTypeDeclaration.length();
126
127 if ((length == 0) || (sbTypeDeclaration.charAt(length-1) == '/')) {
128 sbTypeDeclaration.append(typeName);
129 } else {
130 sbTypeDeclaration.append('$').append(typeName);
131 }
132
133 String internalTypeName = sbTypeDeclaration.toString();
134 typeDeclarationSet.add(internalTypeName);
135 nameToInternalTypeName.put(typeName, internalTypeName);
136
137 HashSet<String> superInternalTypeNameSet = new HashSet<>();
138
139 // Add super type reference
140 JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
141 if (superType != null) {
142 String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
143
144 if (superQualifiedTypeName.charAt(0) != '*')
145 superInternalTypeNameSet.add(superQualifiedTypeName);
146 }
147
148 // Add implementation references
149 JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0);
150 if (superInterfaces != null) {
151 for (JavaParser.TypeContext superInterface : superInterfaces.type()) {
152 String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier());
153
154 if (superQualifiedInterfaceName.charAt(0) != '*')
155 superInternalTypeNameSet.add(superQualifiedInterfaceName);
156 }
157 }
158
159 if (! superInternalTypeNameSet.isEmpty()) {
160 superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet);
124 TerminalNode identifier = ctx.getToken(JavaParser.Identifier, 0);
125
126 if (identifier != null) {
127 String typeName = identifier.getText();
128 int length = sbTypeDeclaration.length();
129
130 if ((length == 0) || (sbTypeDeclaration.charAt(length - 1) == '/')) {
131 sbTypeDeclaration.append(typeName);
132 } else {
133 sbTypeDeclaration.append('$').append(typeName);
134 }
135
136 String internalTypeName = sbTypeDeclaration.toString();
137 typeDeclarationSet.add(internalTypeName);
138 nameToInternalTypeName.put(typeName, internalTypeName);
139
140 HashSet<String> superInternalTypeNameSet = new HashSet<>();
141
142 // Add super type reference
143 JavaParser.TypeContext superType = ctx.getRuleContext(JavaParser.TypeContext.class, 0);
144 if (superType != null) {
145 String superQualifiedTypeName = resolveInternalTypeName(superType.classOrInterfaceType().Identifier());
146
147 if (superQualifiedTypeName.charAt(0) != '*')
148 superInternalTypeNameSet.add(superQualifiedTypeName);
149 }
150
151 // Add implementation references
152 JavaParser.TypeListContext superInterfaces = ctx.getRuleContext(JavaParser.TypeListContext.class, 0);
153 if (superInterfaces != null) {
154 for (JavaParser.TypeContext superInterface : superInterfaces.type()) {
155 String superQualifiedInterfaceName = resolveInternalTypeName(superInterface.classOrInterfaceType().Identifier());
156
157 if (superQualifiedInterfaceName.charAt(0) != '*')
158 superInternalTypeNameSet.add(superQualifiedInterfaceName);
159 }
160 }
161
162 if (!superInternalTypeNameSet.isEmpty()) {
163 superTypeNamesMap.put(internalTypeName, superInternalTypeNameSet);
164 }
161165 }
162166 }
163167
196200
197201 public void enterFieldDeclaration(JavaParser.FieldDeclarationContext ctx) {
198202 for (JavaParser.VariableDeclaratorContext declaration : ctx.variableDeclarators().variableDeclarator()) {
199 String name = declaration.variableDeclaratorId().Identifier().getText();
200 fieldDeclarationSet.add(name);
203 TerminalNode identifier = declaration.variableDeclaratorId().Identifier();
204
205 if (identifier != null) {
206 String name = identifier.getText();
207 fieldDeclarationSet.add(name);
208 }
201209 }
202210 }
203211
204212 public void enterMethodDeclaration(JavaParser.MethodDeclarationContext ctx) {
205 String name = ctx.Identifier().getText();
206 methodDeclarationSet.add(name);
213 TerminalNode identifier = ctx.Identifier();
214
215 if (identifier != null) {
216 String name = identifier.getText();
217 methodDeclarationSet.add(name);
218 }
207219 }
208220
209221 public void enterInterfaceMethodDeclaration(JavaParser.InterfaceMethodDeclarationContext ctx) {
210 String name = ctx.Identifier().getText();
211 methodDeclarationSet.add(name);
222 TerminalNode identifier = ctx.Identifier();
223
224 if (identifier != null) {
225 String name = identifier.getText();
226 methodDeclarationSet.add(name);
227 }
212228 }
213229
214230 public void enterConstructorDeclaration(JavaParser.ConstructorDeclarationContext ctx) {
281297 protected TerminalNode getRightTerminalNode(ParseTree pt) {
282298 if (pt instanceof ParserRuleContext) {
283299 List<ParseTree> children = ((ParserRuleContext)pt).children;
284 int size = children.size();
285
286 if (size > 0) {
287 ParseTree last = children.get(size - 1);
288
289 if (last instanceof TerminalNode) {
290 return (TerminalNode) last;
291 } else {
292 return getRightTerminalNode(last);
300
301 if (children != null) {
302 int size = children.size();
303
304 if (size > 0) {
305 ParseTree last = children.get(size - 1);
306
307 if (last instanceof TerminalNode) {
308 return (TerminalNode) last;
309 } else {
310 return getRightTerminalNode(last);
311 }
293312 }
294313 }
295314 }
2020 import java.io.File;
2121 import java.io.IOException;
2222 import java.io.InputStream;
23 import java.util.regex.Pattern;
2324
2425 public class ClassFileTreeNodeFactoryProvider extends AbstractTypeFileTreeNodeFactoryProvider {
2526 protected static final ImageIcon CLASS_FILE_ICON = new ImageIcon(ClassFileTreeNodeFactoryProvider.class.getClassLoader().getResource("org/jd/gui/images/classf_obj.png"));
3536 }
3637
3738 @Override public String[] getSelectors() { return appendSelectors("*:file:*.class"); }
39
40 @Override
41 public Pattern getPathPattern() {
42 if (externalPathPattern == null) {
43 return Pattern.compile("^((?!module-info\\.class).)*$");
44 } else {
45 return externalPathPattern;
46 }
47 }
3848
3949 @Override
4050 @SuppressWarnings("unchecked")
4242
4343 @Override
4444 public String makeTip(API api, Container.Entry entry) {
45 File file = new File(entry.getContainer().getRoot().getUri());
45 String location = new File(entry.getUri()).getPath();
4646 StringBuilder tip = new StringBuilder("<html>Location: ");
4747
48 tip.append(file.getPath());
48 tip.append(location);
4949 tip.append("</html>");
5050
5151 return tip.toString();
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.service.treenode;
8
9 import org.jd.gui.api.API;
10 import org.jd.gui.api.feature.ContainerEntryGettable;
11 import org.jd.gui.api.feature.UriGettable;
12 import org.jd.gui.api.model.Container;
13 import org.jd.gui.util.exception.ExceptionUtil;
14 import org.jd.gui.view.component.ModuleInfoFilePage;
15 import org.jd.gui.view.data.TreeNodeBean;
16
17 import javax.swing.*;
18 import javax.swing.tree.DefaultMutableTreeNode;
19 import java.io.File;
20 import java.util.regex.Pattern;
21
22 public class ModuleInfoFileTreeNodeFactoryProvider extends ClassFileTreeNodeFactoryProvider {
23 protected static final Factory FACTORY = new Factory();
24
25 static {
26 // Early class loading
27 try {
28 Class.forName(ModuleInfoFilePage.class.getName());
29 } catch (Exception e) {
30 assert ExceptionUtil.printStackTrace(e);
31 }
32 }
33
34 @Override public String[] getSelectors() { return appendSelectors("*:file:*/module-info.class"); }
35
36 @Override public Pattern getPathPattern() { return externalPathPattern; }
37
38 @Override
39 @SuppressWarnings("unchecked")
40 public <T extends DefaultMutableTreeNode & ContainerEntryGettable & UriGettable> T make(API api, Container.Entry entry) {
41 int lastSlashIndex = entry.getPath().lastIndexOf('/');
42 String label = entry.getPath().substring(lastSlashIndex+1);
43 return (T)new FileTreeNode(entry, new TreeNodeBean(label, CLASS_FILE_ICON), FACTORY);
44 }
45
46 protected static class Factory implements AbstractTypeFileTreeNodeFactoryProvider.PageAndTipFactory {
47 // --- PageAndTipFactory --- //
48 @Override
49 @SuppressWarnings("unchecked")
50 public <T extends JComponent & UriGettable> T makePage(API a, Container.Entry e) {
51 return (T)new ModuleInfoFilePage(a, e);
52 }
53
54 @Override
55 public String makeTip(API api, Container.Entry entry) {
56 String location = new File(entry.getUri()).getPath();
57 StringBuilder tip = new StringBuilder("<html>Location: ");
58
59 tip.append(location);
60 tip.append("</html>");
61
62 return tip.toString();
63 }
64 }
65 }
113113 typeNameCache.put(name, qualifiedName);
114114 return qualifiedName;
115115 }
116 } catch (ClassNotFoundException e) {
117 assert ExceptionUtil.printStackTrace(e);
116 } catch (ClassNotFoundException ignore) {
117 // Ignore class loading error
118118 }
119119
120120 // Type not found
170170
171171 if (!foldsExpanded) {
172172 try {
173 Rectangle r = textArea.modelToView(start);
174
175 if (r != null) {
173 Rectangle rec = textArea.modelToView(start);
174
175 if (rec != null) {
176176 // Visible
177 setCaretPositionAndCenter(start, end, r);
177 setCaretPositionAndCenter(start, end, rec);
178178 } else {
179179 // Not visible yet
180 SwingUtilities.invokeLater(new Runnable() {
181 public void run() {
182 try {
183 Rectangle r = textArea.modelToView(start);
184 if (r != null) {
185 setCaretPositionAndCenter(start, end, r);
186 }
187 } catch (BadLocationException e) {
188 assert ExceptionUtil.printStackTrace(e);
180 SwingUtilities.invokeLater(() -> {
181 try {
182 Rectangle r = textArea.modelToView(start);
183 if (r != null) {
184 setCaretPositionAndCenter(start, end, r);
189185 }
186 } catch (BadLocationException e) {
187 assert ExceptionUtil.printStackTrace(e);
190188 }
191189 });
192190 }
8383
8484 // Decompile class file
8585 DECOMPILER.decompile(loader, printer, entryInternalName, configuration);
86 setText(printer.getStringBuffer().toString());
8786 } catch (Throwable t) {
8887 assert ExceptionUtil.printStackTrace(t);
8988 setText("// INTERNAL ERROR //");
153152 }
154153 }
155154
155 @Override
156 public void end() {
157 setText(stringBuffer.toString());
158 }
159
156160 // --- Add strings --- //
157161 @Override
158162 public void printStringConstant(String constant, String ownerInternalName) {
4444 protected int[] lineNumberMap = null;
4545 protected int maxLineNumber = 0;
4646
47 public void setMaxLineNumber(int maxLineNumber) {
47 protected void setMaxLineNumber(int maxLineNumber) {
4848 if (maxLineNumber > 0) {
4949 if (lineNumberMap == null) {
50 lineNumberMap = new int[maxLineNumber * 3 / 2];
50 lineNumberMap = new int[maxLineNumber+1];
5151 } else if (lineNumberMap.length <= maxLineNumber) {
52 int[] tmp = new int[maxLineNumber * 3 / 2];
52 int[] tmp = new int[maxLineNumber+1];
5353 System.arraycopy(lineNumberMap, 0, tmp, 0, lineNumberMap.length);
5454 lineNumberMap = tmp;
5555 }
5656
57 if (this.maxLineNumber < maxLineNumber) {
58 this.maxLineNumber = maxLineNumber;
59 }
60 }
61 }
62
63 public void initLineNumbers(int maxLineNumber) {
64 setMaxLineNumber(maxLineNumber);
65
66 for (int i=1; i<=maxLineNumber; i++) {
67 lineNumberMap[i] = i;
68 }
69 }
70
71 public void setLineNumber(int textAreaLineNumber, int originalLineNumber) {
57 this.maxLineNumber = maxLineNumber;
58 }
59 }
60
61 protected void initLineNumbers() {
62 String text = getText();
63 int len = text.length();
64
65 if (len == 0) {
66 setMaxLineNumber(0);
67 } else {
68 int mln = len - text.replace("\n", "").length();
69
70 if (text.charAt(len-1) != '\n') {
71 mln++;
72 }
73
74 setMaxLineNumber(mln);
75
76 for (int i=1; i<=maxLineNumber; i++) {
77 lineNumberMap[i] = i;
78 }
79 }
80 }
81
82 protected void setLineNumber(int textAreaLineNumber, int originalLineNumber) {
7283 if (originalLineNumber > 0) {
7384 setMaxLineNumber(textAreaLineNumber);
7485 lineNumberMap[textAreaLineNumber] = originalLineNumber;
7586 }
7687 }
7788
78 public void clearLineNumbers() {
89 protected void clearLineNumbers() {
7990 if (lineNumberMap != null) {
8091 Arrays.fill(lineNumberMap, 0);
8192 }
8293 }
8394
84 public int getMaximumSourceLineNumber() { return maxLineNumber; }
85
86 public int getTextAreaLineNumber(int originalLineNumber) {
95 protected int getMaximumSourceLineNumber() { return maxLineNumber; }
96
97 protected int getTextAreaLineNumber(int originalLineNumber) {
8798 int textAreaLineNumber = 1;
8899 int greatestLowerSourceLineNumber = 0;
89100 int i = lineNumberMap.length;
3939 referenceListener.init(declarationListener);
4040 ANTLRJavaParser.parse(new ANTLRInputStream(text), referenceListener);
4141 // Display
42 initLineNumbers(getMaxLineNumber(text));
4342 setText(text);
44 }
45
46 private static int getMaxLineNumber(String text) {
47 return text.length() - text.replace("\n", "").length();
43 initLineNumbers();
4844 }
4945
5046 public String getSyntaxStyle() { return SyntaxConstants.SYNTAX_STYLE_JAVA; }
395391 }
396392 }
397393 }
398 } else {
394 } else if (ctx.primary() != null) {
399395 TerminalNode identifier = ctx.primary().Identifier();
400396
401397 if (identifier != null) {
0 /*
1 * Copyright (c) 2008-2019 Emmanuel Dupuy.
2 * This project is distributed under the GPLv3 license.
3 * This is a Copyleft license that gives the user the right to use,
4 * copy and modify the code freely for non-commercial purposes.
5 */
6
7 package org.jd.gui.view.component;
8
9 import org.fife.ui.rsyntaxtextarea.*;
10 import org.jd.gui.api.API;
11 import org.jd.gui.api.model.Container;
12 import org.jd.gui.util.decompiler.ContainerLoader;
13 import org.jd.gui.util.exception.ExceptionUtil;
14
15 import javax.swing.text.Segment;
16 import java.util.Map;
17
18 public class ModuleInfoFilePage extends ClassFilePage {
19 public static final String SYNTAX_STYLE_JAVA_MODULE = "text/java-module";
20
21 static {
22 // Add a new token maker for Java 9+ module
23 AbstractTokenMakerFactory atmf = (AbstractTokenMakerFactory)TokenMakerFactory.getDefaultInstance();
24 atmf.putMapping(SYNTAX_STYLE_JAVA_MODULE, ModuleInfoTokenMaker.class.getName());
25 }
26
27 public ModuleInfoFilePage(API api, Container.Entry entry) {
28 super(api, entry);
29 }
30
31 public void decompile(Map<String, String> preferences) {
32 try {
33 // Clear ...
34 clearHyperlinks();
35 clearLineNumbers();
36 typeDeclarations.clear();
37
38 // Init preferences
39 boolean unicodeEscape = getPreferenceValue(preferences, ESCAPE_UNICODE_CHARACTERS, false);
40
41 // Init loader
42 ContainerLoader loader = new ContainerLoader(entry);
43
44 // Init printer
45 ModuleInfoFilePrinter printer = new ModuleInfoFilePrinter();
46 printer.setUnicodeEscape(unicodeEscape);
47
48 // Format internal name
49 String entryPath = entry.getPath();
50 assert entryPath.endsWith(".class");
51 String entryInternalName = entryPath.substring(0, entryPath.length() - 6); // 6 = ".class".length()
52
53 // Decompile class file
54 DECOMPILER.decompile(loader, printer, entryInternalName);
55 } catch (Throwable t) {
56 assert ExceptionUtil.printStackTrace(t);
57 setText("// INTERNAL ERROR //");
58 }
59 }
60
61 public String getSyntaxStyle() { return SYNTAX_STYLE_JAVA_MODULE; }
62
63 public class ModuleInfoFilePrinter extends ClassFilePrinter {
64 @Override
65 public void start(int maxLineNumber, int majorVersion, int minorVersion) {}
66
67 @Override
68 public void end() {
69 setText(stringBuffer.toString());
70 initLineNumbers();
71 }
72 }
73
74 // https://github.com/bobbylight/RSyntaxTextArea/wiki/Adding-Syntax-Highlighting-for-a-new-Language
75 public static class ModuleInfoTokenMaker extends AbstractTokenMaker {
76 @Override
77 public TokenMap getWordsToHighlight() {
78 TokenMap tokenMap = new TokenMap();
79
80 tokenMap.put("exports", Token.RESERVED_WORD);
81 tokenMap.put("module", Token.RESERVED_WORD);
82 tokenMap.put("open", Token.RESERVED_WORD);
83 tokenMap.put("opens", Token.RESERVED_WORD);
84 tokenMap.put("provides", Token.RESERVED_WORD);
85 tokenMap.put("requires", Token.RESERVED_WORD);
86 tokenMap.put("to", Token.RESERVED_WORD);
87 tokenMap.put("transitive", Token.RESERVED_WORD);
88 tokenMap.put("uses", Token.RESERVED_WORD);
89 tokenMap.put("with", Token.RESERVED_WORD);
90
91 return tokenMap;
92 }
93
94 @Override
95 public void addToken(Segment segment, int start, int end, int tokenType, int startOffset) {
96 // This assumes all keywords, etc. were parsed as "identifiers."
97 if (tokenType==Token.IDENTIFIER) {
98 int value = wordsToHighlight.get(segment, start, end);
99 if (value != -1) {
100 tokenType = value;
101 }
102 }
103 super.addToken(segment, start, end, tokenType, startOffset);
104 }
105
106 @Override
107 public Token getTokenList(Segment text, int startTokenType, int startOffset) {
108 resetTokenList();
109
110 char[] array = text.array;
111 int offset = text.offset;
112 int end = offset + text.count;
113
114 int newStartOffset = startOffset - offset;
115
116 int currentTokenStart = offset;
117 int currentTokenType = startTokenType;
118
119 for (int i=offset; i<end; i++) {
120 char c = array[i];
121
122 switch (currentTokenType) {
123 case Token.NULL:
124 currentTokenStart = i; // Starting a new token here.
125 if (RSyntaxUtilities.isLetter(c) || c=='_') {
126 currentTokenType = Token.IDENTIFIER;
127 } else {
128 currentTokenType = Token.WHITESPACE;
129 }
130 break;
131 default: // Should never happen
132 case Token.WHITESPACE:
133 if (RSyntaxUtilities.isLetterOrDigit(c) || c=='_') {
134 addToken(text, currentTokenStart, i-1, Token.WHITESPACE, newStartOffset+currentTokenStart);
135 currentTokenStart = i;
136 currentTokenType = Token.IDENTIFIER;
137 }
138 break;
139 case Token.IDENTIFIER:
140 if (!RSyntaxUtilities.isLetterOrDigit(c) && c!='_') {
141 addToken(text, currentTokenStart, i-1, Token.IDENTIFIER, newStartOffset+currentTokenStart);
142 currentTokenStart = i;
143 currentTokenType = Token.WHITESPACE;
144 }
145 break;
146 }
147 }
148
149 if (currentTokenType == Token.NULL) {
150 addNullToken();
151 }else {
152 addToken(text, currentTokenStart,end-1, currentTokenType, newStartOffset+currentTokenStart);
153 addNullToken();
154 }
155
156 return firstToken;
157 }
158 }
159 }
1616 org.jd.gui.service.treenode.ManifestFileTreeNodeFactoryProvider
1717 org.jd.gui.service.treenode.MetainfDirectoryTreeNodeFactoryProvider
1818 org.jd.gui.service.treenode.MetainfServiceFileTreeNodeFactoryProvider
19 org.jd.gui.service.treenode.ModuleInfoFileTreeNodeFactoryProvider
1920 org.jd.gui.service.treenode.PackageTreeNodeFactoryProvider
2021 org.jd.gui.service.treenode.PropertiesFileTreeNodeFactoryProvider
2122 org.jd.gui.service.treenode.SqlFileTreeNodeFactoryProvider