55import java .io .IOException ;
66import java .io .InputStream ;
77import java .lang .management .ManagementFactory ;
8+ import java .net .URI ;
9+ import java .nio .file .FileSystems ;
810import java .nio .file .FileVisitResult ;
911import java .nio .file .Files ;
1012import java .nio .file .Path ;
1416import java .util .*;
1517import java .util .function .Supplier ;
1618import java .util .stream .Collectors ;
17- import java .util .zip .ZipEntry ;
18- import java .util .zip .ZipInputStream ;
19+ import java .util .zip .ZipFile ;
1920
2021import javax .annotation .Nonnull ;
2122import javax .annotation .Nullable ;
@@ -52,27 +53,77 @@ public static class SystemClassPath {
5253 public static final ClassPath SYSTEM_CLASS_PATH = makeSystemJarClassPath ();
5354
5455 private static ClassPath makeSystemJarClassPath () {
55- // TODO: handle java 9 JRT (jrt:// path)
56- // Easy solution: delegate to system classloader
57-
5856 // only scan java/ files in boot class path
5957 // avoid JVM/JDK internals
60- val paths = Splitter .pathSplitter .split (ManagementFactory .getRuntimeMXBean ().getBootClassPath ())
61- .map (it -> Paths .get (it )).filter (it -> it .getFileName ().toString ().equals ("rt.jar" ))
62- .collect (Collectors .toList ());
63- return new FileClassPath (null , paths );
58+ try {
59+ val paths = Splitter .pathSplitter .split (ManagementFactory .getRuntimeMXBean ().getBootClassPath ())
60+ .map (it -> Paths .get (it )).filter (it -> it .getFileName ().toString ().equals ("rt.jar" ))
61+ .collect (Collectors .toList ());
62+ return new FileClassPath (null , paths );
63+ } catch (UnsupportedOperationException ignored ) {
64+ val fs = FileSystems .getFileSystem (URI .create ("jrt:/" ));
65+ return new FileClassPath (null , Collections .singletonList (fs .getPath ("modules/java.base/" )));
66+ }
6467 }
6568 }
6669
67- static class FileClassPath implements ClassPath , TypeSolver {
70+ private static abstract class ClassPathSolver implements ClassPath , TypeSolver {
6871 @ Nullable
6972 final ClassPath parent ;
73+
74+ ClassPathSolver (@ Nullable ClassPath parent ) {
75+ this .parent = parent ;
76+ }
77+
78+ @ Override
79+ public TypeSolver getParent () {
80+ return parent instanceof TypeSolver ? (TypeSolver ) parent : null ;
81+ }
82+
83+ @ Override
84+ public void setParent (TypeSolver parent ) {
85+ throw new UnsupportedOperationException ("TODO" );
86+ }
87+
88+ static Path normalise (Path path ) {
89+ return path .toAbsolutePath ().normalize ();
90+ }
91+
92+ @ NonNull
93+ @ Override
94+ public SymbolReference <ResolvedReferenceTypeDeclaration > tryToSolveType (String name ) {
95+ val ci = getClassInfo (name );
96+ if (ci == null ) {
97+ return SymbolReference .unsolved (ResolvedReferenceTypeDeclaration .class );
98+ }
99+ return SymbolReference .solved (getResolvedReferenceTypeDeclarationForClassInfo (ci ));
100+ }
101+
102+ private ResolvedReferenceTypeDeclaration getResolvedReferenceTypeDeclarationForClassInfo (ClassInfo ci ) {
103+ if (ci instanceof SourceInfo ) {
104+ val jpType = ((SourceInfo ) ci ).getJavaParserType ();
105+ if (jpType .isClassOrInterfaceDeclaration ()) {
106+ return new JavaParserClassDeclaration (jpType .asClassOrInterfaceDeclaration (), this );
107+ } else if (jpType .isEnumDeclaration ()) {
108+ return new JavaParserEnumDeclaration (jpType .asEnumDeclaration (), this );
109+ } else if (jpType .isAnnotationDeclaration ()) {
110+ return new JavaParserAnnotationDeclaration (jpType .asAnnotationDeclaration (), this );
111+ }
112+ }
113+ if (ci instanceof ByteCodeInfo ) {
114+ return AsmResolvedTypes .fromByteCodeInfo (this , (ByteCodeInfo ) ci );
115+ }
116+ throw new UnsupportedOperationException ("TODO " + ci );
117+ }
118+ }
119+
120+ static class FileClassPath extends ClassPathSolver {
70121 private final Map <String , ClassInfo > entries = new HashMap <>();
71122 private final Collection <Path > paths ;
72123 private boolean initialised ;
73124
74125 public FileClassPath (@ Nullable ClassPath parent , Collection <Path > paths ) {
75- this . parent = parent ;
126+ super ( parent ) ;
76127 this .paths = paths ;
77128 }
78129
@@ -90,10 +141,6 @@ public ClassInfo getClassInfo(@Nonnull String className) {
90141 return entries .get (className );
91142 }
92143
93- private static Path normalise (Path path ) {
94- return path .toAbsolutePath ().normalize ();
95- }
96-
97144 @ Override
98145 public synchronized boolean addPath (Path path ) {
99146 path = normalise (path );
@@ -131,11 +178,8 @@ private void findPaths(String entryName, Supplier<InputStream> iss) {
131178 }
132179
133180 if (entryName .endsWith (".class" )) {
134- try (val is = iss .get ()) {
135- String name = JVMUtil .fileNameToClassName (entryName );
136- val classNode = AsmUtil .getClassNode (StreamUtil .readFully (is ), null );
137- entries .put (name , new ByteCodeInfo (() -> classNode , name , Collections .emptyMap ()));
138- }
181+ String name = JVMUtil .fileNameToClassName (entryName );
182+ entries .put (name , new ByteCodeInfo (() -> AsmUtil .getClassNode (StreamUtil .readFully (iss .get ()), null ), name , Collections .emptyMap ()));
139183 }
140184 }
141185
@@ -176,67 +220,23 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
176220 }
177221 });
178222 else if (Files .isRegularFile (path ))
179- try (val zis = new ZipInputStream (Files .newInputStream (path ))) {
180- ZipEntry e ;
181- val is = new InputStream () {
182- public int read (@ NonNull byte [] b , int off , int len ) throws IOException {
183- return zis .read (b , off , len );
184- }
185-
186- public void close () throws IOException {
187- // don't allow closing this ZIS
188- }
189-
190- public int read () throws IOException {
191- return zis .read ();
192- }
193- };
194- while ((e = zis .getNextEntry ()) != null ) {
195- try {
196- findPaths (e .getName (), () -> is );
197- } finally {
198- zis .closeEntry ();
199- }
223+ try (val zf = new ZipFile (path .toFile ())) {
224+ val e$ = zf .entries ();
225+ while (e$ .hasMoreElements ()) {
226+ val ze = e$ .nextElement ();
227+ val name = ze .getName ();
228+ findPaths (name , () -> {
229+ try {
230+ val zff = new ZipFile (path .toFile ());
231+ return zff .getInputStream (zff .getEntry (name ));
232+ } catch (IOException e ) {
233+ throw new IOError (e );
234+ }
235+ });
200236 }
201237 }
202238 }
203239
204- @ Override
205- public TypeSolver getParent () {
206- return null ;
207- }
208-
209- @ Override
210- public void setParent (TypeSolver parent ) {
211- throw new UnsupportedOperationException ("TODO" );
212- }
213-
214- @ NonNull
215- @ Override
216- public SymbolReference <ResolvedReferenceTypeDeclaration > tryToSolveType (String name ) {
217- val ci = getClassInfo (name );
218- if (ci == null ) {
219- return SymbolReference .unsolved (ResolvedReferenceTypeDeclaration .class );
220- }
221- return SymbolReference .solved (getResolvedReferenceTypeDeclarationForClassInfo (ci ));
222- }
223-
224- private ResolvedReferenceTypeDeclaration getResolvedReferenceTypeDeclarationForClassInfo (ClassInfo ci ) {
225- if (ci instanceof SourceInfo ) {
226- val jpType = ((SourceInfo ) ci ).getJavaParserType ();
227- if (jpType .isClassOrInterfaceDeclaration ()) {
228- return new JavaParserClassDeclaration (jpType .asClassOrInterfaceDeclaration (), this );
229- } else if (jpType .isEnumDeclaration ()) {
230- return new JavaParserEnumDeclaration (jpType .asEnumDeclaration (), this );
231- } else if (jpType .isAnnotationDeclaration ()) {
232- return new JavaParserAnnotationDeclaration (jpType .asAnnotationDeclaration (), this );
233- }
234- }
235- if (ci instanceof ByteCodeInfo ) {
236- return AsmResolvedTypes .fromByteCodeInfo (this , (ByteCodeInfo ) ci );
237- }
238- throw new UnsupportedOperationException ("TODO " + ci );
239- }
240240 }
241241
242242 /*
0 commit comments