1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.jar.classes;
20
21 import javax.inject.Named;
22 import javax.inject.Singleton;
23
24 import java.io.IOException;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Optional;
30 import java.util.jar.JarEntry;
31
32 import org.apache.bcel.classfile.ClassFormatException;
33 import org.apache.bcel.classfile.ClassParser;
34 import org.apache.bcel.classfile.DescendingVisitor;
35 import org.apache.bcel.classfile.JavaClass;
36 import org.apache.bcel.classfile.LineNumberTable;
37 import org.apache.bcel.classfile.Method;
38 import org.apache.maven.shared.jar.JarAnalyzer;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42
43
44
45
46
47
48
49
50 @Singleton
51 @Named
52 @SuppressWarnings("checkstyle:MagicNumber")
53 public class JarClassesAnalysis {
54 private final Logger logger = LoggerFactory.getLogger(getClass());
55
56 private static final Map<Double, String> JAVA_CLASS_VERSIONS;
57
58 static {
59 HashMap<Double, String> aMap = new HashMap<>();
60 aMap.put(65.0, "21");
61 aMap.put(64.0, "20");
62 aMap.put(63.0, "19");
63 aMap.put(62.0, "18");
64 aMap.put(61.0, "17");
65 aMap.put(60.0, "16");
66 aMap.put(59.0, "15");
67 aMap.put(58.0, "14");
68 aMap.put(57.0, "13");
69 aMap.put(56.0, "12");
70 aMap.put(55.0, "11");
71 aMap.put(54.0, "10");
72 aMap.put(53.0, "9");
73 aMap.put(52.0, "1.8");
74 aMap.put(51.0, "1.7");
75 aMap.put(50.0, "1.6");
76 aMap.put(49.0, "1.5");
77 aMap.put(48.0, "1.4");
78 aMap.put(47.0, "1.3");
79 aMap.put(46.0, "1.2");
80 aMap.put(45.3, "1.1");
81 JAVA_CLASS_VERSIONS = Collections.unmodifiableMap(aMap);
82 }
83
84
85
86
87
88
89
90
91
92 public JarClasses analyze(JarAnalyzer jarAnalyzer) {
93 JarClasses classes = jarAnalyzer.getJarData().getJarClasses();
94 if (classes == null) {
95 String jarfilename = jarAnalyzer.getFile().getAbsolutePath();
96 classes = new JarClasses();
97
98 List<JarEntry> classList = jarAnalyzer.getClassEntries();
99
100 classes.setDebugPresent(false);
101
102 double maxVersion = 0.0;
103
104 for (JarEntry entry : classList) {
105 String classname = entry.getName();
106
107 try {
108 ClassParser classParser = new ClassParser(jarfilename, classname);
109
110 JavaClass javaClass = classParser.parse();
111
112 String classSignature = javaClass.getClassName();
113
114 if (!classes.isDebugPresent()) {
115 if (hasDebugSymbols(javaClass)) {
116 classes.setDebugPresent(true);
117 }
118 }
119
120 double classVersion = javaClass.getMajor();
121 if (javaClass.getMinor() > 0) {
122 classVersion = classVersion + javaClass.getMinor() / 10.0;
123 }
124
125 if (classVersion > maxVersion) {
126 maxVersion = classVersion;
127 }
128
129 Method[] methods = javaClass.getMethods();
130 for (Method method : methods) {
131 classes.addMethod(classSignature + "." + method.getName() + method.getSignature());
132 }
133
134 String classPackageName = javaClass.getPackageName();
135
136 classes.addClassName(classSignature);
137 classes.addPackage(classPackageName);
138
139 ImportVisitor importVisitor = new ImportVisitor(javaClass);
140 DescendingVisitor descVisitor = new DescendingVisitor(javaClass, importVisitor);
141 javaClass.accept(descVisitor);
142
143 classes.addImports(importVisitor.getImports());
144 } catch (ClassFormatException e) {
145 logger.warn("Unable to process class " + classname + " in JarAnalyzer File " + jarfilename, e);
146 } catch (IOException e) {
147 logger.warn("Unable to process JarAnalyzer File " + jarfilename, e);
148 }
149 }
150
151 Optional.ofNullable(JAVA_CLASS_VERSIONS.get(maxVersion)).ifPresent(classes::setJdkRevision);
152
153 jarAnalyzer.getJarData().setJarClasses(classes);
154 }
155 return classes;
156 }
157
158 private boolean hasDebugSymbols(JavaClass javaClass) {
159 boolean ret = false;
160 Method[] methods = javaClass.getMethods();
161 for (Method method : methods) {
162 LineNumberTable linenumbers = method.getLineNumberTable();
163 if (linenumbers != null && linenumbers.getLength() > 0) {
164 ret = true;
165 break;
166 }
167 }
168 return ret;
169 }
170 }