IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
VfsAssemblyClassDirectory.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Concurrent;
3using System.Collections.Generic;
4using System.Linq;
5using System.Reflection;
6
7using IKVM.Runtime;
9
11{
12
16 internal sealed class VfsAssemblyClassDirectory : VfsDirectory
17 {
18
19 readonly Assembly assembly;
20 readonly JavaPackageName package;
21 readonly ConcurrentDictionary<string, VfsEntry> cache = new();
22
30 public VfsAssemblyClassDirectory(VfsContext context, Assembly assembly, JavaPackageName package) :
31 base(context)
32 {
33 this.assembly = assembly ?? throw new ArgumentNullException(nameof(assembly));
34 this.package = package;
35 }
36
42 public override VfsEntry GetEntry(string name)
43 {
44 return cache.GetOrAdd(name, CreateEntry);
45 }
46
52 VfsEntry CreateEntry(string name)
53 {
54 if (name.EndsWith(".class", StringComparison.Ordinal))
55 return GetClassEntry(new JavaTypeName(package, new JavaUnqualifiedTypeName(name.Substring(0, name.Length - ".class".Length))));
56 else
57 return GetPackageEntry(new JavaPackageName(package, name));
58 }
59
65 RuntimeJavaType TryLoadType(JavaTypeName className)
66 {
67#if FIRST_PASS || IMPORTER || EXPORTER
68 throw new NotImplementedException();
69#else
70 var acl = Context.Context.AssemblyClassLoaderFactory.FromAssembly(assembly);
71
72 try
73 {
74 return acl.TryLoadClassByName(className);
75 }
76 catch
77 {
78
79 }
80
81 return null;
82#endif
83 }
84
91 VfsEntry GetClassEntry(JavaTypeName className)
92 {
93 return TryLoadType(className) is RuntimeJavaType tw && !tw.IsArray ? new VfsAssemblyClassFile(Context, tw) : null;
94 }
95
100 IEnumerable<Type> GetAssemblyTypes()
101 {
102 try
103 {
104 return assembly.GetTypes();
105 }
106 catch (ReflectionTypeLoadException e)
107 {
108 return e.Types;
109 }
110 catch
111 {
112 return Type.EmptyTypes;
113 }
114 }
115
122 VfsEntry GetPackageEntry(JavaPackageName packageName)
123 {
124#if FIRST_PASS || IMPORTER || EXPORTER
125 throw new PlatformNotSupportedException();
126#else
127 var acl = Context.Context.AssemblyClassLoaderFactory.FromAssembly(assembly);
128 if (acl == null)
129 throw new InvalidOperationException("Could not locate assembly loader.");
130
131 // search for any type that would be within the package
132 foreach (var type in GetAssemblyTypes())
133 {
134 // attempt to find Java type name
135 var name = acl.GetTypeNameAndType(type, out var isJavaType);
136 if (name is null)
137 continue;
138
139 // annotation custom attributes are pseudo proxies and are not loadable by name (and should not exist in the file systems,
140 // because proxies are, ostensibly, created on the fly)
141 if (isJavaType && type.BaseType == typeof(global::ikvm.@internal.AnnotationAttributeBase) && name.Value.Value.Span.Contains(".$Proxy".AsSpan(), StringComparison.Ordinal))
142 continue;
143
144 // found a class that is a member of the package, or whose package is a child of the package, it must exist
145 if (name.Value.IsMemberOf(packageName) || name.Value.PackageName.IsChildOf(packageName))
146 return new VfsAssemblyClassDirectory(Context, assembly, packageName);
147 }
148
149 return null;
150#endif
151 }
152
158 public override string[] List()
159 {
160#if FIRST_PASS || IMPORTER || EXPORTER
161 throw new PlatformNotSupportedException();
162#else
163 var lst = new HashSet<string>();
164
165 var acl = Context.Context.AssemblyClassLoaderFactory.FromAssembly(assembly);
166 if (acl == null)
167 throw new InvalidOperationException("Could not locate assembly loader.");
168
169 // search for any type that would be within the package
170 foreach (var type in GetAssemblyTypes())
171 {
172 var name = acl.GetTypeNameAndType(type, out var isJavaType);
173 if (name is null)
174 continue;
175
176 // annotation custom attributes are pseudo proxies and are not loadable by name (and should not exist in the file systems,
177 // because proxies are, ostensibly, created on the fly)
178 if (isJavaType && type.BaseType == typeof(global::ikvm.@internal.AnnotationAttributeBase) && name.Value.Value.Span.Contains(".$Proxy".AsSpan(), StringComparison.Ordinal))
179 continue;
180
181 // found a type that is within the package
182 // its package's simple name is a directory
183 if (name.Value.IsMemberOf(package))
184 {
185 lst.Add(name.Value.UnqualifiedName.ToString() + ".class");
186 continue;
187 }
188
189 // found a type that is within a package which is a child of this package
190 // its package's next segments are directories
191 if (name.Value.PackageName.IsChildOf(package))
192 {
193 var m = true;
194 var o = new ReadOnlySpanSeparatorEnumerator(package.Value.Span, '.');
195 var e = new ReadOnlySpanSeparatorEnumerator(name.Value.PackageName.Value.Span, '.');
196
197 // advance past the matching package name
198 while (o.MoveNext())
199 e.MoveNext();
200
201 // the next component of the package name is a directory
202 if (m && e.MoveNext())
203 lst.Add(e.Current.ToString());
204
205 continue;
206 }
207 }
208
209 return lst.ToArray();
210#endif
211 }
212
213 }
214
215}
IKVM.Reflection.Type Type
IKVM.Reflection.Assembly Assembly
RuntimeAssemblyClassLoader FromAssembly(Assembly assembly)
Obtains the RuntimeAssemblyClassLoader for the given Assembly. This method should not be used with dy...
RuntimeAssemblyClassLoaderFactory AssemblyClassLoaderFactory
Gets the RuntimeAssemblyClassLoaderFactory associated with this instance of the runtime.
Provides methods to parse a Java package name.
Provides methods to parse a Java class name.
Provides methods to parse a Java class name without package.