private static CustomAttributeData GetAnnotationDefault(MethodBase mb) { #if STUB_GENERATOR IList <CustomAttributeData> attr = CustomAttributeData.__GetCustomAttributes(mb, JVM.LoadType(typeof(AnnotationDefaultAttribute)), false); return(attr.Count == 1 ? attr[0] : null); #else foreach (CustomAttributeData cad in CustomAttributeData.GetCustomAttributes(mb)) { if (cad.Constructor.DeclaringType == typeof(AnnotationDefaultAttribute)) { return(cad); } } return(null); #endif }
private static void WriteClass(TypeWrapper tw) { string name = tw.Name.Replace('.', '/'); string super = null; if (tw.IsInterface) { super = "java/lang/Object"; } else if (tw.BaseTypeWrapper != null) { super = tw.BaseTypeWrapper.Name.Replace('.', '/'); } IKVM.StubGen.ClassFileWriter writer = new IKVM.StubGen.ClassFileWriter(tw.Modifiers, name, super, 0, 49); foreach (TypeWrapper iface in tw.Interfaces) { if (iface.IsPublic || includeNonPublicInterfaces) { writer.AddInterface(iface.Name.Replace('.', '/')); } } IKVM.StubGen.InnerClassesAttribute innerClassesAttribute = null; if (tw.DeclaringTypeWrapper != null) { TypeWrapper outer = tw.DeclaringTypeWrapper; string innername = name; int idx = name.LastIndexOf('$'); if (idx >= 0) { innername = innername.Substring(idx + 1); } innerClassesAttribute = new IKVM.StubGen.InnerClassesAttribute(writer); innerClassesAttribute.Add(name, outer.Name.Replace('.', '/'), innername, (ushort)tw.ReflectiveModifiers); } foreach (TypeWrapper inner in tw.InnerClasses) { if (inner.IsPublic) { if (innerClassesAttribute == null) { innerClassesAttribute = new IKVM.StubGen.InnerClassesAttribute(writer); } string namePart = inner.Name; namePart = namePart.Substring(namePart.LastIndexOf('$') + 1); innerClassesAttribute.Add(inner.Name.Replace('.', '/'), name, namePart, (ushort)inner.ReflectiveModifiers); } } if (innerClassesAttribute != null) { writer.AddAttribute(innerClassesAttribute); } string genericTypeSignature = tw.GetGenericSignature(); if (genericTypeSignature != null) { writer.AddStringAttribute("Signature", genericTypeSignature); } writer.AddStringAttribute("IKVM.NET.Assembly", GetAssemblyName(tw)); if (tw.TypeAsBaseType.IsDefined(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false)) { writer.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); } foreach (MethodWrapper mw in tw.GetMethods()) { if (!mw.IsHideFromReflection && (mw.IsPublic || mw.IsProtected || includeNonPublicMembers)) { IKVM.StubGen.FieldOrMethod m; if (mw.Name == "<init>") { m = writer.AddMethod(mw.Modifiers, mw.Name, mw.Signature.Replace('.', '/')); IKVM.StubGen.CodeAttribute code = new IKVM.StubGen.CodeAttribute(writer); code.MaxLocals = (ushort)(mw.GetParameters().Length * 2 + 1); code.MaxStack = 3; ushort index1 = writer.AddClass("java/lang/UnsatisfiedLinkError"); ushort index2 = writer.AddString("ikvmstub generated stubs can only be used on IKVM.NET"); ushort index3 = writer.AddMethodRef("java/lang/UnsatisfiedLinkError", "<init>", "(Ljava/lang/String;)V"); code.ByteCode = new byte[] { 187, (byte)(index1 >> 8), (byte)index1, // new java/lang/UnsatisfiedLinkError 89, // dup 19, (byte)(index2 >> 8), (byte)index2, // ldc_w "..." 183, (byte)(index3 >> 8), (byte)index3, // invokespecial java/lang/UnsatisfiedLinkError/init()V 191 // athrow }; m.AddAttribute(code); } else { Modifiers mods = mw.Modifiers; if ((mods & Modifiers.Abstract) == 0) { mods |= Modifiers.Native; } m = writer.AddMethod(mods, mw.Name, mw.Signature.Replace('.', '/')); if (mw.IsOptionalAttributeAnnotationValue) { m.AddAttribute(new IKVM.StubGen.AnnotationDefaultClassFileAttribute(writer, GetAnnotationDefault(writer, mw.ReturnType))); } } MethodBase mb = mw.GetMethod(); if (mb != null) { ThrowsAttribute throws = AttributeHelper.GetThrows(mb); if (throws == null) { string[] throwsArray = mw.GetDeclaredExceptions(); if (throwsArray != null && throwsArray.Length > 0) { IKVM.StubGen.ExceptionsAttribute attrib = new IKVM.StubGen.ExceptionsAttribute(writer); foreach (string ex in throwsArray) { attrib.Add(ex.Replace('.', '/')); } m.AddAttribute(attrib); } } else { IKVM.StubGen.ExceptionsAttribute attrib = new IKVM.StubGen.ExceptionsAttribute(writer); if (throws.classes != null) { foreach (string ex in throws.classes) { attrib.Add(ex.Replace('.', '/')); } } if (throws.types != null) { foreach (Type ex in throws.types) { attrib.Add(ClassLoaderWrapper.GetWrapperFromType(ex).Name.Replace('.', '/')); } } m.AddAttribute(attrib); } if (mb.IsDefined(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false) // HACK the instancehelper methods are marked as Obsolete (to direct people toward the ikvm.extensions methods instead) // but in the Java world most of them are not deprecated (and to keep the Japi results clean we need to reflect this) && (!mb.Name.StartsWith("instancehelper_") || mb.DeclaringType.FullName != "java.lang.String" // the Java deprecated methods actually have two Obsolete attributes || mb.__GetCustomAttributes(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false).Count == 2)) { m.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); } IList <CustomAttributeData> attr = CustomAttributeData.__GetCustomAttributes(mb, JVM.LoadType(typeof(AnnotationDefaultAttribute)), false); if (attr.Count == 1) { m.AddAttribute(new IKVM.StubGen.AnnotationDefaultClassFileAttribute(writer, GetAnnotationDefault(writer, attr[0].ConstructorArguments[0]))); } } string sig = tw.GetGenericMethodSignature(mw); if (sig != null) { m.AddAttribute(writer.MakeStringAttribute("Signature", sig)); } } } bool hasSerialVersionUID = false; foreach (FieldWrapper fw in tw.GetFields()) { if (!fw.IsHideFromReflection) { bool isSerialVersionUID = includeSerialVersionUID && fw.Name == "serialVersionUID" && fw.FieldTypeWrapper == PrimitiveTypeWrapper.LONG; hasSerialVersionUID |= isSerialVersionUID; if (fw.IsPublic || fw.IsProtected || isSerialVersionUID || includeNonPublicMembers) { object constant = null; if (fw.GetField() != null && fw.GetField().IsLiteral&& (fw.FieldTypeWrapper.IsPrimitive || fw.FieldTypeWrapper == CoreClasses.java.lang.String.Wrapper)) { constant = fw.GetField().GetRawConstantValue(); if (fw.GetField().FieldType.IsEnum) { constant = EnumHelper.GetPrimitiveValue(EnumHelper.GetUnderlyingType(fw.GetField().FieldType), constant); } } IKVM.StubGen.FieldOrMethod f = writer.AddField(fw.Modifiers, fw.Name, fw.Signature.Replace('.', '/'), constant); string sig = tw.GetGenericFieldSignature(fw); if (sig != null) { f.AddAttribute(writer.MakeStringAttribute("Signature", sig)); } if (fw.GetField() != null && fw.GetField().IsDefined(StaticCompiler.Universe.Import(typeof(ObsoleteAttribute)), false)) { f.AddAttribute(new IKVM.StubGen.DeprecatedAttribute(writer)); } } } } if (includeSerialVersionUID && !hasSerialVersionUID && IsSerializable(tw)) { // class is serializable but doesn't have an explicit serialVersionUID, so we add the field to record // the serialVersionUID as we see it (mainly to make the Japi reports more realistic) writer.AddField(Modifiers.Private | Modifiers.Static | Modifiers.Final, "serialVersionUID", "J", IKVM.StubGen.SerialVersionUID.Compute(tw)); } AddMetaAnnotations(writer, tw); zipCount++; MemoryStream mem = new MemoryStream(); writer.Write(mem); ZipEntry entry = new ZipEntry(name + ".class"); entry.Size = mem.Position; zipFile.PutNextEntry(entry); mem.WriteTo(zipFile); }