IKVM11  11
Java SE 11 Virtual Machine for .NET
Loading...
Searching...
No Matches
Annotation.cs
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2015 Jeroen Frijters
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any damages
6 arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any purpose,
9 including commercial applications, and to alter it and redistribute it
10 freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must not
13 claim that you wrote the original software. If you use this software
14 in a product, an acknowledgment in the product documentation would be
15 appreciated but is not required.
16 2. Altered source versions must be plainly marked as such, and must not be
17 misrepresented as being the original software.
18 3. This notice may not be removed or altered from any source distribution.
19
20 Jeroen Frijters
21 jeroen@frijters.net
22
23*/
24using System;
25using System.Diagnostics;
26
27using IKVM.Attributes;
28
29
30
31#if IMPORTER || EXPORTER
32using IKVM.Reflection;
34
35using Type = IKVM.Reflection.Type;
36
37using System.Collections;
38using System.Collections.Generic;
39
40#else
41using System.Reflection;
42using System.Reflection.Emit;
43#endif
44
45#if IMPORTER
47#endif
48
49namespace IKVM.Runtime
50{
51
52 abstract class Annotation
53 {
54
55#if IMPORTER
56
57 internal static Annotation LoadAssemblyCustomAttribute(RuntimeClassLoader loader, object[] def)
58 {
59 if (def.Length == 0)
60 throw new ArgumentException("LoadAssemblyCustomAttribute did not receive any definitions.");
61 if (object.Equals(def[0], AnnotationDefaultAttribute.TAG_ANNOTATION) == false)
62 throw new InternalException("LoadAssemblyCustomAttribute did not receive AnnotationDefaultAttribute.TAG_ANNOTATION.");
63
64 var annotationClass = (string)def[1];
65
66 if (ClassFile.IsValidFieldDescriptor(annotationClass))
67 {
68 try
69 {
70 return loader.RetTypeWrapperFromSig(annotationClass.Replace('/', '.'), LoadMode.LoadOrThrow).Annotation;
71 }
73 {
74
75 }
76 }
77
78 return null;
79 }
80
81#endif
82
83#if !EXPORTER
84
85 // NOTE this method returns null if the type could not be found
86 // or if the type is not a Custom Attribute and we're not in the static compiler
87 internal static Annotation Load(RuntimeJavaType owner, object[] def)
88 {
89 Debug.Assert(def[0].Equals(AnnotationDefaultAttribute.TAG_ANNOTATION));
90
91 var annotationClass = (string)def[1];
92#if !IMPORTER
93 if (!annotationClass.EndsWith("$Annotation;") && !annotationClass.EndsWith("$Annotation$__ReturnValue;") && !annotationClass.EndsWith("$Annotation$__Multiple;"))
94 {
95 // we don't want to try to load an annotation in dynamic mode,
96 // unless it is a .NET custom attribute (which can affect runtime behavior)
97 return null;
98 }
99#endif
100
101 if (ClassFile.IsValidFieldDescriptor(annotationClass))
102 {
103 var tw = owner.ClassLoader.RetTypeWrapperFromSig(annotationClass.Replace('/', '.'), LoadMode.Link);
104 // Java allows inaccessible annotations to be used, so when the annotation isn't visible
105 // we fall back to using the DynamicAnnotationAttribute.
106 if (!tw.IsUnloadable && tw.IsAccessibleFrom(owner))
107 {
108 return tw.Annotation;
109 }
110 }
111
112 owner.Diagnostics.GenericCompilerWarning($"Unable to load annotation class {annotationClass}");
113#if IMPORTER
114 return new RuntimeManagedByteCodeJavaType.CompiledAnnotation(owner.Context, owner.Context.Resolver.ResolveRuntimeType("IKVM.Attributes.DynamicAnnotationAttribute").AsReflection());
115#else
116 return null;
117#endif
118 }
119
120#endif
121
122 private static object LookupEnumValue(RuntimeContext context, Type enumType, string value)
123 {
124 FieldInfo field = enumType.GetField(value, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
125 if (field != null)
126 {
127 return field.GetRawConstantValue();
128 }
129 // both __unspecified and missing values end up here
130 return EnumHelper.GetPrimitiveValue(context, EnumHelper.GetUnderlyingType(enumType), 0);
131 }
132
133 protected static object ConvertValue(RuntimeClassLoader loader, Type targetType, object obj)
134 {
135 if (targetType.IsEnum)
136 {
137 // TODO check the obj descriptor matches the type we expect
138 if (((object[])obj)[0].Equals(AnnotationDefaultAttribute.TAG_ARRAY))
139 {
140 object[] arr = (object[])obj;
141 object value = null;
142 for (int i = 1; i < arr.Length; i++)
143 {
144 // TODO check the obj descriptor matches the type we expect
145 string s = ((object[])arr[i])[2].ToString();
146 object newval = LookupEnumValue(loader.Context, targetType, s);
147 if (value == null)
148 {
149 value = newval;
150 }
151 else
152 {
153 value = EnumHelper.OrBoxedIntegrals(loader.Context, value, newval);
154 }
155 }
156 return value;
157 }
158 else
159 {
160 string s = ((object[])obj)[2].ToString();
161 if (s == "__unspecified")
162 {
163 // TODO we should probably return null and handle that
164 }
165 return LookupEnumValue(loader.Context, targetType, s);
166 }
167 }
168 else if (targetType == loader.Context.Types.Type)
169 {
170 // TODO check the obj descriptor matches the type we expect
171 return loader.FieldTypeWrapperFromSig(((string)((object[])obj)[1]).Replace('/', '.'), LoadMode.LoadOrThrow).TypeAsTBD;
172 }
173 else if (targetType.IsArray)
174 {
175 // TODO check the obj descriptor matches the type we expect
176 object[] arr = (object[])obj;
177 Type elementType = targetType.GetElementType();
178 object[] targetArray = new object[arr.Length - 1];
179 for (int i = 1; i < arr.Length; i++)
180 {
181 targetArray[i - 1] = ConvertValue(loader, elementType, arr[i]);
182 }
183 return targetArray;
184 }
185 else
186 {
187 return obj;
188 }
189 }
190
191 internal static bool HasRetentionPolicyRuntime(object[] annotations)
192 {
193 if (annotations != null)
194 {
195 foreach (object[] def in annotations)
196 {
197 if (def[1].Equals("Ljava/lang/annotation/Retention;"))
198 {
199 for (int i = 2; i < def.Length; i += 2)
200 {
201 if (def[i].Equals("value"))
202 {
203 object[] val = def[i + 1] as object[];
204 if (val != null
205 && val.Length == 3
206 && val[0].Equals(AnnotationDefaultAttribute.TAG_ENUM)
207 && val[1].Equals("Ljava/lang/annotation/RetentionPolicy;")
208 && val[2].Equals("RUNTIME"))
209 {
210 return true;
211 }
212 }
213 }
214 }
215 }
216 }
217
218 return false;
219 }
220
221 internal static bool HasObsoleteAttribute(object[] annotations)
222 {
223 if (annotations != null)
224 {
225 foreach (object[] def in annotations)
226 {
227 if (def[1].Equals("Lcli/System/ObsoleteAttribute$Annotation;"))
228 {
229 return true;
230 }
231 }
232 }
233
234 return false;
235 }
236
237 protected static object QualifyClassNames(RuntimeClassLoader loader, object annotation)
238 {
239 bool copy = false;
240 object[] def = (object[])annotation;
241 for (int i = 3; i < def.Length; i += 2)
242 {
243 object[] val = def[i] as object[];
244 if (val != null)
245 {
246 object[] newval = ValueQualifyClassNames(loader, val);
247 if (newval != val)
248 {
249 if (!copy)
250 {
251 copy = true;
252 object[] newdef = new object[def.Length];
253 Array.Copy(def, newdef, def.Length);
254 def = newdef;
255 }
256 def[i] = newval;
257 }
258 }
259 }
260 return def;
261 }
262
263 static object[] ValueQualifyClassNames(RuntimeClassLoader loader, object[] val)
264 {
266 {
267 return (object[])QualifyClassNames(loader, val);
268 }
269 else if (val[0].Equals(AnnotationDefaultAttribute.TAG_CLASS))
270 {
271 var sig = (string)val[1];
272 if (sig.StartsWith("L", StringComparison.Ordinal))
273 {
274 var tw = loader.TryLoadClassByName(sig.Substring(1, sig.Length - 2).Replace('/', '.'));
275 if (tw != null)
276 return [AnnotationDefaultAttribute.TAG_CLASS, "L" + tw.TypeAsBaseType.AssemblyQualifiedName.Replace('.', '/') + ";"];
277 }
278 return val;
279 }
280 else if (val[0].Equals(AnnotationDefaultAttribute.TAG_ENUM))
281 {
282 var sig = (string)val[1];
283 var tw = loader.TryLoadClassByName(sig.Substring(1, sig.Length - 2).Replace('/', '.'));
284 if (tw != null)
285 return [AnnotationDefaultAttribute.TAG_ENUM, "L" + tw.TypeAsBaseType.AssemblyQualifiedName.Replace('.', '/') + ";", val[2]];
286
287 return val;
288 }
289 else if (val[0].Equals(AnnotationDefaultAttribute.TAG_ARRAY))
290 {
291 var copy = false;
292 for (int i = 1; i < val.Length; i++)
293 {
294 if (val[i] is object[] nval)
295 {
296 var newnval = ValueQualifyClassNames(loader, nval);
297 if (newnval != nval)
298 {
299 if (copy == false)
300 {
301 copy = true;
302 var newval = new object[val.Length];
303 Array.Copy(val, newval, val.Length);
304 val = newval;
305 }
306
307 val[i] = newnval;
308 }
309 }
310 }
311
312 return val;
313 }
314 else if (val[0].Equals(AnnotationDefaultAttribute.TAG_ERROR))
315 {
316 return val;
317 }
318 else
319 {
320 throw new InvalidOperationException();
321 }
322 }
323
324 internal abstract void Apply(RuntimeClassLoader loader, TypeBuilder tb, object annotation);
325 internal abstract void Apply(RuntimeClassLoader loader, MethodBuilder mb, object annotation);
326 internal abstract void Apply(RuntimeClassLoader loader, FieldBuilder fb, object annotation);
327 internal abstract void Apply(RuntimeClassLoader loader, ParameterBuilder pb, object annotation);
328 internal abstract void Apply(RuntimeClassLoader loader, AssemblyBuilder ab, object annotation);
329 internal abstract void Apply(RuntimeClassLoader loader, PropertyBuilder pb, object annotation);
330
331 internal virtual void ApplyReturnValue(RuntimeClassLoader loader, MethodBuilder mb, ref ParameterBuilder pb, object annotation)
332 {
333
334 }
335
336 internal abstract bool IsCustomAttribute { get; }
337
338 }
339
340}
IKVM.Reflection.Type Type
IKVM.Reflection.FieldInfo FieldInfo
static object ConvertValue(RuntimeClassLoader loader, Type targetType, object obj)
static object QualifyClassNames(RuntimeClassLoader loader, object annotation)
static bool IsValidFieldDescriptor(string descriptor)
Returns true if the specified descriptor is a valid field descriptor.
Definition ClassFile.cs:152
Represents an internal error that occurred within IKVM.
.NET exception that corresponds to a Java exception.
Runtime support for a class loader.
RuntimeContext Context
Gets a reference to the RuntimeContext that this RuntimeClassLoader is hosted within.
Maintains services relevant to an instane of the IKVM runtime.
Types Types
Gets the Types associated with this instance of the runtime.
ISymbolResolver Resolver
Gets the ISymbolResolver associated with this instance of the runtime.
Represents a runtime Java type derived from a .NET assembly which was the result of the IKVM compiler...
void GenericCompilerWarning(string arg0)
The 'GenericCompilerWarning' diagnostic.