• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 Federico Tomassetti
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5  * in compliance with the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License
10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11  * or implied. See the License for the specific language governing permissions and limitations under
12  * the License.
13  */
14 
15 package com.github.javaparser.symbolsolver.resolution.typesolvers;
16 
17 import com.github.javaparser.resolution.UnsolvedSymbolException;
18 import com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration;
19 import com.github.javaparser.symbolsolver.javassistmodel.JavassistFactory;
20 import com.github.javaparser.symbolsolver.model.resolution.SymbolReference;
21 import com.github.javaparser.symbolsolver.model.resolution.TypeSolver;
22 import javassist.ClassPool;
23 import javassist.CtClass;
24 import javassist.NotFoundException;
25 
26 import java.io.*;
27 import java.util.Enumeration;
28 import java.util.HashMap;
29 import java.util.Map;
30 import java.util.jar.JarEntry;
31 import java.util.jar.JarFile;
32 
33 /**
34  * @author Federico Tomassetti
35  */
36 public class JarTypeSolver implements TypeSolver {
37 
38     private static JarTypeSolver instance;
39 
40     private TypeSolver parent;
41     private Map<String, ClasspathElement> classpathElements = new HashMap<>();
42     private ClassPool classPool = new ClassPool(false);
43 
JarTypeSolver(String pathToJar)44     public JarTypeSolver(String pathToJar) throws IOException {
45         addPathToJar(pathToJar);
46     }
47 
JarTypeSolver(InputStream jarInputStream)48     public JarTypeSolver(InputStream jarInputStream) throws IOException {
49         addPathToJar(jarInputStream);
50     }
51 
getJarTypeSolver(String pathToJar)52     public static JarTypeSolver getJarTypeSolver(String pathToJar) throws IOException {
53         if (instance == null) {
54             instance = new JarTypeSolver(pathToJar);
55         } else {
56             instance.addPathToJar(pathToJar);
57         }
58         return instance;
59     }
60 
dumpToTempFile(InputStream inputStream)61     private File dumpToTempFile(InputStream inputStream) throws IOException {
62         File tempFile = File.createTempFile("jar_file_from_input_stream", ".jar");
63         tempFile.deleteOnExit();
64 
65         byte[] buffer = new byte[8 * 1024];
66 
67         try {
68             OutputStream output = new FileOutputStream(tempFile);
69             try {
70                 int bytesRead;
71                 while ((bytesRead = inputStream.read(buffer)) != -1) {
72                     output.write(buffer, 0, bytesRead);
73                 }
74             } finally {
75                 output.close();
76             }
77         } finally {
78             inputStream.close();
79         }
80         return tempFile;
81     }
82 
addPathToJar(InputStream jarInputStream)83     private void addPathToJar(InputStream jarInputStream) throws IOException {
84         addPathToJar(dumpToTempFile(jarInputStream).getAbsolutePath());
85     }
86 
addPathToJar(String pathToJar)87     private void addPathToJar(String pathToJar) throws IOException {
88         try {
89             classPool.appendClassPath(pathToJar);
90             classPool.appendSystemPath();
91         } catch (NotFoundException e) {
92             throw new RuntimeException(e);
93         }
94         JarFile jarFile = new JarFile(pathToJar);
95         JarEntry entry = null;
96         Enumeration<JarEntry> e = jarFile.entries();
97         while (e.hasMoreElements()) {
98             entry = e.nextElement();
99             if (entry != null && !entry.isDirectory() && entry.getName().endsWith(".class")) {
100                 String name = entryPathToClassName(entry.getName());
101                 classpathElements.put(name, new ClasspathElement(jarFile, entry, name));
102             }
103         }
104     }
105 
106     @Override
getParent()107     public TypeSolver getParent() {
108         return parent;
109     }
110 
111     @Override
setParent(TypeSolver parent)112     public void setParent(TypeSolver parent) {
113         this.parent = parent;
114     }
115 
entryPathToClassName(String entryPath)116     private String entryPathToClassName(String entryPath) {
117         if (!entryPath.endsWith(".class")) {
118             throw new IllegalStateException();
119         }
120         String className = entryPath.substring(0, entryPath.length() - ".class".length());
121         className = className.replace('/', '.');
122         className = className.replace('$', '.');
123         return className;
124     }
125 
126     @Override
tryToSolveType(String name)127     public SymbolReference<ResolvedReferenceTypeDeclaration> tryToSolveType(String name) {
128         try {
129             if (classpathElements.containsKey(name)) {
130                 return SymbolReference.solved(
131                         JavassistFactory.toTypeDeclaration(classpathElements.get(name).toCtClass(), getRoot()));
132             } else {
133                 return SymbolReference.unsolved(ResolvedReferenceTypeDeclaration.class);
134             }
135         } catch (IOException e) {
136             throw new RuntimeException(e);
137         }
138     }
139 
140     @Override
solveType(String name)141     public ResolvedReferenceTypeDeclaration solveType(String name) throws UnsolvedSymbolException {
142         SymbolReference<ResolvedReferenceTypeDeclaration> ref = tryToSolveType(name);
143         if (ref.isSolved()) {
144             return ref.getCorrespondingDeclaration();
145         } else {
146             throw new UnsolvedSymbolException(name);
147         }
148     }
149 
150     private class ClasspathElement {
151         private JarFile jarFile;
152         private JarEntry entry;
153         private String path;
154 
ClasspathElement(JarFile jarFile, JarEntry entry, String path)155         ClasspathElement(JarFile jarFile, JarEntry entry, String path) {
156             this.jarFile = jarFile;
157             this.entry = entry;
158             this.path = path;
159         }
160 
toCtClass()161         CtClass toCtClass() throws IOException {
162             try (InputStream is = jarFile.getInputStream(entry)) {
163                 return classPool.makeClass(is);
164             }
165         }
166     }
167 }
168