ikvm-fork/ikvmstub/ikvmstub.cs

712 строки
19 KiB
C#
Исходник Обычный вид История

2002-12-18 19:00:25 +03:00
/*
2005-02-02 18:11:26 +03:00
Copyright (C) 2002, 2004, 2005 Jeroen Frijters
2002-12-18 19:00:25 +03:00
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Jeroen Frijters
jeroen@frijters.net
*/
using System;
using System.Reflection;
using System.IO;
using System.Text;
2003-10-22 20:34:22 +04:00
using System.Collections;
2003-01-08 16:35:05 +03:00
using ICSharpCode.SharpZipLib.Zip;
2004-09-09 15:17:55 +04:00
using IKVM.Attributes;
using IKVM.Internal;
2002-12-18 19:00:25 +03:00
public class NetExp
{
private static ZipOutputStream zipFile;
2003-10-22 20:34:22 +04:00
private static Hashtable privateClasses = new Hashtable();
2002-12-18 19:00:25 +03:00
public static void Main(string[] args)
{
2004-03-08 18:18:47 +03:00
Tracer.EnableTraceForDebug();
2004-06-07 12:28:57 +04:00
if(args.Length != 1)
{
Console.Error.WriteLine("usage: ikvmstub <assemblyNameOrPath>");
return;
}
2002-12-18 19:00:25 +03:00
Assembly assembly = null;
2004-06-07 12:28:57 +04:00
FileInfo file = null;
try
{
file = new FileInfo(args[0]);
}
catch(System.Exception x)
{
Console.Error.WriteLine("Error: unable to load \"{0}\"\n {1}", args[0], x.Message);
return;
}
if(file != null && file.Exists)
2002-12-18 19:00:25 +03:00
{
2003-08-26 15:24:17 +04:00
try
{
// If the same assembly can be found in the "Load" context, we prefer to use that
// http://blogs.gotdotnet.com/suzcook/permalink.aspx/d5c5e14a-3612-4af1-a9b7-0a144c8dbf16
// We use AssemblyName.FullName, because otherwise the assembly will be loaded in the
// "LoadFrom" context using the path inside the AssemblyName object.
assembly = Assembly.Load(AssemblyName.GetAssemblyName(args[0]).FullName);
Console.Error.WriteLine("Warning: Assembly loaded from {0} instead", assembly.Location);
}
catch
{
}
if(assembly == null)
{
assembly = Assembly.LoadFrom(args[0]);
}
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else
{
assembly = Assembly.LoadWithPartialName(args[0]);
}
2005-02-02 18:11:26 +03:00
int rc = 0;
2002-12-18 19:00:25 +03:00
if(assembly == null)
{
Console.Error.WriteLine("Error: Assembly \"{0}\" not found", args[0]);
}
else
{
2003-01-08 16:35:05 +03:00
zipFile = new ZipOutputStream(new FileStream(assembly.GetName().Name + ".jar", FileMode.Create));
2004-12-21 13:26:51 +03:00
try
{
ProcessAssembly(assembly);
ProcessPrivateClasses(assembly);
}
catch(System.Exception x)
{
java.lang.Throwable.instancehelper_printStackTrace(IKVM.Runtime.Util.MapException(x));
2005-02-02 18:11:26 +03:00
rc = 1;
2004-12-21 13:26:51 +03:00
}
2003-08-21 14:06:34 +04:00
zipFile.Close();
2002-12-18 19:00:25 +03:00
}
2004-05-25 11:14:39 +04:00
// FXBUG if we run a static initializer that starts a thread, we would never end,
2003-08-21 14:06:34 +04:00
// so we force an exit here
2005-02-02 18:11:26 +03:00
Environment.Exit(rc);
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
private static void WriteClass(string name, ClassFileWriter c)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
zipFile.PutNextEntry(new ZipEntry(name));
c.Write(zipFile);
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
private static void ProcessAssembly(Assembly assembly)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
foreach(Type t in assembly.GetTypes())
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if(t.IsPublic)
2002-12-18 19:00:25 +03:00
{
2005-02-02 18:11:26 +03:00
java.lang.Class c;
2004-10-04 23:30:53 +04:00
try
{
2005-02-02 18:11:26 +03:00
c = java.lang.Class.forName(t.AssemblyQualifiedName, false, null);
2004-10-04 23:30:53 +04:00
}
2005-02-02 18:11:26 +03:00
catch(java.lang.ClassNotFoundException)
2004-10-04 23:30:53 +04:00
{
// types that IKVM doesn't support don't show up
continue;
}
ProcessClass(assembly.FullName, c, null);
2002-12-18 19:00:25 +03:00
}
}
}
2003-11-17 15:01:50 +03:00
// TODO private classes should also be done handled for interfaces, fields and method arguments/return type
2003-10-22 20:34:22 +04:00
private static void ProcessPrivateClasses(Assembly assembly)
{
Hashtable done = new Hashtable();
bool keepGoing;
do
{
Hashtable todo = privateClasses;
privateClasses = new Hashtable();
keepGoing = false;
2005-02-02 18:11:26 +03:00
foreach(java.lang.Class c in todo.Values)
2003-10-22 20:34:22 +04:00
{
if(!done.ContainsKey(c.getName()))
{
keepGoing = true;
done.Add(c.getName(), null);
ProcessClass(assembly.FullName, c, c.getDeclaringClass());
}
}
} while(keepGoing);
}
2005-06-22 17:02:03 +04:00
private static void AddToExportList(java.lang.Class c)
{
2005-06-22 18:24:16 +04:00
while(c.isArray())
{
c = c.getComponentType();
}
2005-06-22 17:02:03 +04:00
privateClasses[c.getName()] = c;
}
private static bool IsGenericType(java.lang.Class c)
{
// HACK huge hack, we look for the backtick
2005-11-14 12:12:08 +03:00
return c.getName().IndexOf("$$0060") > 0;
2005-06-22 17:02:03 +04:00
}
2005-02-02 18:11:26 +03:00
private static void ProcessClass(string assemblyName, java.lang.Class c, java.lang.Class outer)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
string name = c.getName().Replace('.', '/');
string super = null;
if(c.getSuperclass() != null)
2003-04-14 13:41:58 +04:00
{
2003-08-21 14:06:34 +04:00
super = c.getSuperclass().getName().Replace('.', '/');
2003-10-22 20:34:22 +04:00
// if the base class isn't public, we still need to export it (!)
2005-02-02 18:11:26 +03:00
if(!java.lang.reflect.Modifier.isPublic(c.getSuperclass().getModifiers()))
2003-10-22 20:34:22 +04:00
{
2005-06-22 17:02:03 +04:00
AddToExportList(c.getSuperclass());
2003-10-22 20:34:22 +04:00
}
2003-04-14 13:41:58 +04:00
}
2003-08-21 14:06:34 +04:00
if(c.isInterface())
2002-12-18 19:00:25 +03:00
{
super = "java/lang/Object";
}
2004-02-18 16:48:38 +03:00
Modifiers classmods = (Modifiers)c.getModifiers();
if(outer != null)
{
// protected inner classes are actually public and private inner classes are actually package
if((classmods & Modifiers.Protected) != 0)
{
classmods |= Modifiers.Public;
}
classmods &= ~(Modifiers.Static | Modifiers.Private | Modifiers.Protected);
}
2005-10-01 15:16:11 +04:00
#if GENERICS
if(c.isAnnotation())
{
classmods |= Modifiers.Annotation;
}
if(c.isEnum())
{
classmods |= Modifiers.Enum;
}
if(c.isSynthetic())
{
classmods |= Modifiers.Synthetic;
}
ClassFileWriter f = new ClassFileWriter(classmods, name, super, 0, 49);
string genericSignature = BuildGenericSignature(c);
if(genericSignature != null)
{
f.AddStringAttribute("Signature", genericSignature);
}
#else
ClassFileWriter f = new ClassFileWriter(classmods, name, super, 3, 45);
#endif
2003-08-21 14:06:34 +04:00
f.AddStringAttribute("IKVM.NET.Assembly", assemblyName);
2004-11-16 14:11:53 +03:00
if(IKVM.Runtime.Util.IsClassDeprecated(c))
{
f.AddAttribute(new DeprecatedAttribute(f));
}
2003-08-21 14:06:34 +04:00
InnerClassesAttribute innerClassesAttribute = null;
if(outer != null)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
innerClassesAttribute = new InnerClassesAttribute(f);
2004-02-10 12:53:56 +03:00
string innername = name;
int idx = name.LastIndexOf('$');
if(idx >= 0)
{
innername = innername.Substring(idx + 1);
}
innerClassesAttribute.Add(name, outer.getName().Replace('.', '/'), innername, (ushort)c.getModifiers());
2002-12-18 19:00:25 +03:00
}
2005-02-02 18:11:26 +03:00
java.lang.Class[] interfaces = c.getInterfaces();
2003-11-17 15:01:50 +03:00
for(int i = 0; i < interfaces.Length; i++)
{
2005-02-02 18:11:26 +03:00
if(java.lang.reflect.Modifier.isPublic(interfaces[i].getModifiers()))
2003-11-17 15:01:50 +03:00
{
f.AddInterface(interfaces[i].getName().Replace('.', '/'));
2005-06-22 17:02:03 +04:00
if(IsGenericType(interfaces[i]))
{
AddToExportList(interfaces[i]);
}
2003-11-17 15:01:50 +03:00
}
}
2005-02-02 18:11:26 +03:00
java.lang.Class[] innerClasses = c.getDeclaredClasses();
2003-08-21 14:06:34 +04:00
for(int i = 0; i < innerClasses.Length; i++)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
Modifiers mods = (Modifiers)innerClasses[i].getModifiers();
if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if(innerClassesAttribute == null)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
innerClassesAttribute = new InnerClassesAttribute(f);
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
string namePart = innerClasses[i].getName();
namePart = namePart.Substring(namePart.LastIndexOf('$') + 1);
innerClassesAttribute.Add(innerClasses[i].getName().Replace('.', '/'), name, namePart, (ushort)innerClasses[i].getModifiers());
ProcessClass(assemblyName, innerClasses[i], c);
2002-12-18 19:00:25 +03:00
}
}
2005-02-02 18:11:26 +03:00
java.lang.reflect.Constructor[] constructors = c.getDeclaredConstructors();
2002-12-18 19:00:25 +03:00
for(int i = 0; i < constructors.Length; i++)
{
2003-08-21 14:06:34 +04:00
Modifiers mods = (Modifiers)constructors[i].getModifiers();
if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
2002-12-18 19:00:25 +03:00
{
2005-10-01 15:16:11 +04:00
#if GENERICS
if(constructors[i].isSynthetic())
{
mods |= Modifiers.Synthetic;
}
if(constructors[i].isVarArgs())
{
mods |= Modifiers.VarArgs;
}
#endif
2003-11-17 15:01:50 +03:00
// TODO what happens if one of the argument types is non-public?
2004-02-10 12:53:56 +03:00
java.lang.Class[] args = constructors[i].getParameterTypes();
2005-06-22 18:24:16 +04:00
foreach(java.lang.Class arg in args)
{
if(IsGenericType(arg))
{
AddToExportList(arg);
}
}
2004-02-10 12:53:56 +03:00
FieldOrMethod m = f.AddMethod(mods, "<init>", MakeSig(args, java.lang.Void.TYPE));
CodeAttribute code = new CodeAttribute(f);
2004-07-10 11:19:42 +04:00
code.MaxLocals = (ushort)(args.Length * 2 + 1);
2004-02-16 20:23:03 +03:00
code.MaxStack = 3;
ushort index1 = f.AddClass("java/lang/UnsatisfiedLinkError");
2004-05-27 13:32:35 +04:00
ushort index2 = f.AddString("ikvmstub generated stubs can only be used on IKVM.NET");
2004-02-16 20:23:03 +03:00
ushort index3 = f.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
};
2004-02-10 12:53:56 +03:00
m.AddAttribute(code);
2004-11-04 15:50:28 +03:00
AddExceptions(f, m, constructors[i].getExceptionTypes());
2004-11-16 14:11:53 +03:00
if(IKVM.Runtime.Util.IsConstructorDeprecated(constructors[i]))
{
m.AddAttribute(new DeprecatedAttribute(f));
}
2005-10-01 15:16:11 +04:00
#if GENERICS
string signature = BuildGenericSignature(constructors[i].getTypeParameters(),
constructors[i].getGenericParameterTypes(), java.lang.Void.TYPE, constructors[i].getGenericExceptionTypes());
if (signature != null)
{
m.AddAttribute(f.MakeStringAttribute("Signature", signature));
}
#endif
2002-12-18 19:00:25 +03:00
}
}
2005-02-02 18:11:26 +03:00
java.lang.reflect.Method[] methods = c.getDeclaredMethods();
2002-12-18 19:00:25 +03:00
for(int i = 0; i < methods.Length; i++)
{
2005-10-01 15:16:11 +04:00
// FXBUG (?) .NET reflection on java.lang.Object returns toString() twice!
// I didn't want to add the work around to CompiledTypeWrapper, so it's here.
if((c.getName() == "java.lang.Object" || c.getName() == "java.lang.Throwable")
&& methods[i].getName() == "toString")
{
bool found = false;
for(int j = 0; j < i; j++)
{
if(methods[j].getName() == "toString")
{
found = true;
break;
}
}
if(found)
{
continue;
}
}
2003-08-21 14:06:34 +04:00
Modifiers mods = (Modifiers)methods[i].getModifiers();
if((mods & (Modifiers.Public | Modifiers.Protected)) != 0)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if((mods & Modifiers.Abstract) == 0)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
mods |= Modifiers.Native;
2002-12-18 19:00:25 +03:00
}
2005-10-01 15:16:11 +04:00
#if GENERICS
if(methods[i].isBridge())
{
mods |= Modifiers.Bridge;
}
if(methods[i].isSynthetic())
{
mods |= Modifiers.Synthetic;
}
if(methods[i].isVarArgs())
{
mods |= Modifiers.VarArgs;
}
#endif
2003-11-17 15:01:50 +03:00
// TODO what happens if one of the argument types (or the return type) is non-public?
2005-06-22 18:24:16 +04:00
java.lang.Class[] args = methods[i].getParameterTypes();
foreach(java.lang.Class arg in args)
{
if(IsGenericType(arg))
{
AddToExportList(arg);
}
}
java.lang.Class retType = methods[i].getReturnType();
if(IsGenericType(retType))
{
AddToExportList(retType);
}
FieldOrMethod m = f.AddMethod(mods, methods[i].getName(), MakeSig(args, retType));
2004-11-04 15:50:28 +03:00
AddExceptions(f, m, methods[i].getExceptionTypes());
2004-11-16 14:11:53 +03:00
if(IKVM.Runtime.Util.IsMethodDeprecated(methods[i]))
{
m.AddAttribute(new DeprecatedAttribute(f));
}
2005-10-01 15:16:11 +04:00
#if GENERICS
string signature = BuildGenericSignature(methods[i].getTypeParameters(),
methods[i].getGenericParameterTypes(), methods[i].getGenericReturnType(),
methods[i].getGenericExceptionTypes());
if (signature != null)
{
m.AddAttribute(f.MakeStringAttribute("Signature", signature));
}
#endif
2002-12-18 19:00:25 +03:00
}
}
2005-02-02 18:11:26 +03:00
java.lang.reflect.Field[] fields = c.getDeclaredFields();
2003-08-21 14:06:34 +04:00
for(int i = 0; i < fields.Length; i++)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
Modifiers mods = (Modifiers)fields[i].getModifiers();
2004-11-16 14:11:53 +03:00
if((mods & (Modifiers.Public | Modifiers.Protected)) != 0 ||
// Include serialVersionUID field, to make Japitools comparison more acurate
((mods & (Modifiers.Static | Modifiers.Final)) == (Modifiers.Static | Modifiers.Final) &&
fields[i].getName() == "serialVersionUID" && fields[i].getType() == java.lang.Long.TYPE))
2002-12-18 19:00:25 +03:00
{
2005-01-03 11:26:21 +03:00
// we use the IKVM runtime API to get constant value
2004-11-16 14:11:53 +03:00
// NOTE we can't use Field.get() because that will run the static initializer and
// also won't allow us to see the difference between constants and blank final fields.
object constantValue = IKVM.Runtime.Util.GetFieldConstantValue(fields[i]);
if(constantValue != null)
2003-08-21 14:06:34 +04:00
{
2004-11-16 14:11:53 +03:00
if(constantValue is java.lang.Boolean)
2003-08-21 14:06:34 +04:00
{
2004-11-16 14:11:53 +03:00
constantValue = ((java.lang.Boolean)constantValue).booleanValue();
}
else if(constantValue is java.lang.Byte)
{
constantValue = ((java.lang.Byte)constantValue).byteValue();
}
else if(constantValue is java.lang.Short)
{
constantValue = ((java.lang.Short)constantValue).shortValue();
}
else if(constantValue is java.lang.Character)
{
constantValue = ((java.lang.Character)constantValue).charValue();
}
else if(constantValue is java.lang.Integer)
{
constantValue = ((java.lang.Integer)constantValue).intValue();
}
else if(constantValue is java.lang.Long)
{
constantValue = ((java.lang.Long)constantValue).longValue();
}
else if(constantValue is java.lang.Float)
{
constantValue = ((java.lang.Float)constantValue).floatValue();
}
else if(constantValue is java.lang.Double)
{
constantValue = ((java.lang.Double)constantValue).doubleValue();
}
else if(constantValue is string)
{
// no conversion needed
}
else
{
throw new InvalidOperationException();
2003-08-21 14:06:34 +04:00
}
}
2003-11-17 15:01:50 +03:00
// TODO what happens if the field type is non-public?
2005-06-22 18:24:16 +04:00
java.lang.Class fieldType = fields[i].getType();
if(IsGenericType(fieldType))
{
AddToExportList(fieldType);
}
2005-10-01 15:16:11 +04:00
#if GENERICS
if(fields[i].isEnumConstant())
{
mods |= Modifiers.Enum;
}
if(fields[i].isSynthetic())
{
mods |= Modifiers.Synthetic;
}
#endif
2005-06-22 18:24:16 +04:00
FieldOrMethod fld = f.AddField(mods, fields[i].getName(), ClassToSig(fieldType), constantValue);
2004-11-16 14:11:53 +03:00
if(IKVM.Runtime.Util.IsFieldDeprecated(fields[i]))
{
fld.AddAttribute(new DeprecatedAttribute(f));
}
2005-10-01 15:16:11 +04:00
#if GENERICS
if(fields[i].getGenericType() != fieldType)
{
fld.AddAttribute(f.MakeStringAttribute("Signature", ToSigForm(fields[i].getGenericType())));
}
#endif
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
}
if(innerClassesAttribute != null)
{
f.AddAttribute(innerClassesAttribute);
2002-12-18 19:00:25 +03:00
}
WriteClass(name + ".class", f);
}
2005-02-02 18:11:26 +03:00
private static void AddExceptions(ClassFileWriter f, FieldOrMethod m, java.lang.Class[] exceptions)
2004-11-04 15:50:28 +03:00
{
if(exceptions.Length > 0)
{
ExceptionsAttribute attrib = new ExceptionsAttribute(f);
2005-02-02 18:11:26 +03:00
foreach(java.lang.Class x in exceptions)
2004-11-04 15:50:28 +03:00
{
// TODO what happens if one of the exception types is non-public?
attrib.Add(x.getName().Replace('.', '/'));
}
m.AddAttribute(attrib);
}
}
2005-02-02 18:11:26 +03:00
private static string MakeSig(java.lang.Class[] args, java.lang.Class ret)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
StringBuilder sb = new StringBuilder();
sb.Append('(');
for(int i = 0; i < args.Length; i++)
{
sb.Append(ClassToSig(args[i]));
}
sb.Append(')');
sb.Append(ClassToSig(ret));
return sb.ToString();
2002-12-18 19:00:25 +03:00
}
2005-02-02 18:11:26 +03:00
private static string ClassToSig(java.lang.Class c)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if(c.isPrimitive())
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
if(c == java.lang.Void.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "V";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Byte.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "B";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Boolean.TYPE)
2003-02-15 14:18:53 +03:00
{
2003-08-21 14:06:34 +04:00
return "Z";
2003-02-15 14:18:53 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Short.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "S";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Character.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "C";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Integer.TYPE)
2003-02-15 14:18:53 +03:00
{
2003-08-21 14:06:34 +04:00
return "I";
2003-02-15 14:18:53 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Long.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "J";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Float.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "F";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c == java.lang.Double.TYPE)
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "D";
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else
2003-03-31 18:54:35 +04:00
{
2003-08-21 14:06:34 +04:00
throw new InvalidOperationException();
2003-03-31 18:54:35 +04:00
}
2002-12-18 19:00:25 +03:00
}
2003-08-21 14:06:34 +04:00
else if(c.isArray())
2002-12-18 19:00:25 +03:00
{
2003-08-21 14:06:34 +04:00
return "[" + ClassToSig(c.getComponentType());
2002-12-18 19:00:25 +03:00
}
else
{
2003-08-21 14:06:34 +04:00
return "L" + c.getName().Replace('.', '/') + ";";
2002-12-18 19:00:25 +03:00
}
}
2005-10-01 15:16:11 +04:00
#if GENERICS
private static string BuildGenericSignature(java.lang.Class c)
{
bool isgeneric = false;
StringBuilder sb = new StringBuilder();
java.lang.reflect.TypeVariable[] vars = c.getTypeParameters();
if(vars.Length > 0)
{
isgeneric = true;
sb.Append('<');
foreach(java.lang.reflect.TypeVariable t in vars)
{
sb.Append(t.getName());
bool first = true;
foreach(java.lang.reflect.Type bound in t.getBounds())
{
if(first)
{
first = false;
if(bound is java.lang.Class)
{
// HACK I don't really understand what the proper criterion is to decide this
if(((java.lang.Class)bound).isInterface())
{
sb.Append(':');
}
}
}
sb.Append(':').Append(ToSigForm(bound));
}
}
sb.Append('>');
}
java.lang.reflect.Type superclass = c.getGenericSuperclass();
if(superclass == null)
{
sb.Append("Ljava/lang/Object;");
}
else
{
isgeneric |= !(superclass is java.lang.Class);
sb.Append(ToSigForm(superclass));
}
foreach(java.lang.reflect.Type t in c.getGenericInterfaces())
{
isgeneric |= !(t is java.lang.Class);
sb.Append(ToSigForm(t));
}
if(isgeneric)
{
return sb.ToString();
}
return null;
}
private static string BuildGenericSignature(java.lang.reflect.TypeVariable[] typeParameters,
java.lang.reflect.Type[] parameterTypes, java.lang.reflect.Type returnType,
java.lang.reflect.Type[] exceptionTypes)
{
StringBuilder sb = new StringBuilder();
if(typeParameters.Length > 0)
{
sb.Append('<');
foreach(java.lang.reflect.TypeVariable t in typeParameters)
{
sb.Append(t.getName());
foreach(java.lang.reflect.Type bound in t.getBounds())
{
sb.Append(':').Append(ToSigForm(bound));
}
}
sb.Append('>');
}
sb.Append('(');
foreach(java.lang.reflect.Type t in parameterTypes)
{
sb.Append(ToSigForm(t));
}
sb.Append(')');
sb.Append(ToSigForm(returnType));
foreach(java.lang.reflect.Type t in exceptionTypes)
{
sb.Append('^').Append(ToSigForm(t));
}
return sb.ToString();
}
private static string ToSigForm(java.lang.reflect.Type t)
{
if(t is java.lang.reflect.ParameterizedType)
{
java.lang.reflect.ParameterizedType p = (java.lang.reflect.ParameterizedType)t;
if(p.getOwnerType() != null)
{
// TODO
throw new NotImplementedException();
}
StringBuilder sb = new StringBuilder();
sb.Append('L').Append(((java.lang.Class)p.getRawType()).getName().Replace('.', '/'));
sb.Append('<');
foreach(java.lang.reflect.Type arg in p.getActualTypeArguments())
{
sb.Append(ToSigForm(arg));
}
sb.Append(">;");
return sb.ToString();
}
else if(t is java.lang.reflect.TypeVariable)
{
return "T" + ((java.lang.reflect.TypeVariable)t).getName() + ";";
}
else if(t is java.lang.reflect.WildcardType)
{
java.lang.reflect.WildcardType w = (java.lang.reflect.WildcardType)t;
java.lang.reflect.Type[] lower = w.getLowerBounds();
java.lang.reflect.Type[] upper = w.getUpperBounds();
if (lower.Length == 0 && upper.Length == 0)
{
return "*";
}
if (lower.Length == 1)
{
return "-" + ToSigForm(lower[0]);
}
if (upper.Length == 1)
{
return "+" + ToSigForm(upper[0]);
}
throw new NotImplementedException();
}
else if(t is java.lang.reflect.GenericArrayType)
{
java.lang.reflect.GenericArrayType a = (java.lang.reflect.GenericArrayType)t;
return "[" + ToSigForm(a.getGenericComponentType());
}
else if(t is java.lang.Class)
{
return ClassToSig((java.lang.Class)t);
}
else
{
throw new NotImplementedException(t.GetType().FullName);
}
}
#endif
2002-12-18 19:00:25 +03:00
}