Skip to content

[Java.Interop.Tools.JavaCallableWrappers] Error on bad IJavaObject #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
//

using System;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.IO;
Expand Down Expand Up @@ -62,20 +63,28 @@ public class DirectoryAssemblyResolver : IAssemblyResolver {

Dictionary<string, AssemblyDefinition> cache;
bool loadDebugSymbols;
Action<string, object[]> logWarnings;
Action<TraceLevel, string> logger;

ReaderParameters loadReaderParameters;

static readonly ReaderParameters DefaultLoadReaderParameters = new ReaderParameters {
};

[Obsolete ("Use DirectoryAssemblyResolver(Action<TraceLevel, string>, bool, ReaderParameters)")]
public DirectoryAssemblyResolver (Action<string, object[]> logWarnings, bool loadDebugSymbols, ReaderParameters loadReaderParameters = null)
: this ((TraceLevel level, string value) => logWarnings?.Invoke ("{0}", new[]{value}), loadDebugSymbols, loadReaderParameters)
{
if (logWarnings == null)
throw new ArgumentNullException (nameof (logWarnings));
}

public DirectoryAssemblyResolver (Action<TraceLevel, string> logger, bool loadDebugSymbols, ReaderParameters loadReaderParameters = null)
{
if (logger == null)
throw new ArgumentNullException (nameof (logger));
cache = new Dictionary<string, AssemblyDefinition> ();
this.loadDebugSymbols = loadDebugSymbols;
this.logWarnings = logWarnings;
this.logger = logger;
SearchDirectories = new List<string> ();
this.loadReaderParameters = loadReaderParameters ?? DefaultLoadReaderParameters;
}
Expand Down Expand Up @@ -141,10 +150,10 @@ protected virtual AssemblyDefinition ReadAssembly (string file)
try {
return AssemblyDefinition.ReadAssembly (file, reader_parameters);
} catch (Exception ex) {
logWarnings (
"Failed to read '{0}' with debugging symbols. Retrying to load it without it. Error details are logged below.",
new [] { file });
logWarnings ("{0}", new [] { ex.ToString () });
logger (
TraceLevel.Warning,
$"Failed to read '{file}' with debugging symbols. Retrying to load it without it. Error details are logged below.");
logger (TraceLevel.Warning, $"{ex.ToString ()}");
reader_parameters.ReadSymbols = false;
return AssemblyDefinition.ReadAssembly (file, reader_parameters);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using System.Collections.Generic;
using System.Diagnostics;

using Mono.Cecil.Cil;

Expand All @@ -27,14 +28,14 @@ namespace Java.Interop.Tools.Diagnostics {
// XA0013 Profiling support requires sgen to be enabled too
// XA0014 iOS {0} does not support building applications targeting ARMv6
// XA0020 Could not launch mandroid daemon.

// XA0100 EmbeddedNativeLibrary '{0}' is invalid in Android Application project. Please use AndroidNativeLibrary instead.
// XA0101 @(Content) build action is not supported
// XA0102 Lint Warning
// XA0103 Lint Error
// XA0104 Invalid Sequence Point mode
// XA0105 The TargetFrameworkVersion for {0} (v{1}) is greater than the TargetFrameworkVersion for your project (v{2}). You need to increase the TargetFrameworkVersion for your project.

// XA1xxx file copy / symlinks (project related)
// XA10xx installer.cs / mtouch.cs
// XA1001 Could not find an application at the specified directory
Expand Down Expand Up @@ -101,6 +102,7 @@ namespace Java.Interop.Tools.Diagnostics {
// XA4209 Failed to create JavaTypeInfo for class: {0} due to {1}
// XA4210 "You need to add a reference to Mono.Android.Export.dll when you use ExportAttribute or ExportFieldAttribute."
// XA4211 AndroidManifest.xml //uses-sdk/@android:targetSdkVersion '{0}' is less than $(TargetFrameworkVersion) '{1}'. Using API-{1} for ACW compilation.
// XA4212 Type `{0}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported.
// XA5xxx GCC and toolchain
// XA32xx .apk generation
// XA4300 Unsupported $(AndroidSupportedAbis) value '{0}'; ignoring.
Expand Down Expand Up @@ -176,6 +178,17 @@ public static void WriteTo (System.IO.TextWriter destination, Exception message,
destination.WriteLine ("monodroid: error XA0000: Unexpected error - Please file a bug report at http://bugzilla.xamarin.com. Reason: {0}",
verbose ? message.Message : message.ToString ());
}

public static Action<TraceLevel, string> CreateConsoleLogger ()
{
Action<TraceLevel, string> logger = (level, value) => {
if (level == TraceLevel.Error)
Console.Error.WriteLine (value);
else
Console.WriteLine (value);
};
return logger;
}
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Mono.Cecil;
Expand All @@ -10,10 +11,19 @@

namespace Java.Interop.Tools.JavaCallableWrappers
{
public static class JavaTypeScanner
public class JavaTypeScanner
{
// Returns all types for which we need to generate Java delegate types.
public static List<TypeDefinition> GetJavaTypes (IEnumerable<string> assemblies, IAssemblyResolver resolver, Action<string, object[]> log)
public Action<TraceLevel, string> Logger { get; private set; }
public bool ErrorOnCustomJavaObject { get; set; }

public JavaTypeScanner (Action<TraceLevel, string> logger)
{
if (logger == null)
throw new ArgumentNullException (nameof (logger));
Logger = logger;
}

public List<TypeDefinition> GetJavaTypes (IEnumerable<string> assemblies, IAssemblyResolver resolver)
{
var javaTypes = new List<TypeDefinition> ();

Expand All @@ -22,32 +32,34 @@ public static List<TypeDefinition> GetJavaTypes (IEnumerable<string> assemblies,

foreach (ModuleDefinition md in assm.Modules) {
foreach (TypeDefinition td in md.Types) {
AddJavaTypes (javaTypes, td, log);
AddJavaTypes (javaTypes, td);
}
}
}

return javaTypes;
}

static void AddJavaTypes (List<TypeDefinition> javaTypes, TypeDefinition type, Action<string, object[]> log)
void AddJavaTypes (List<TypeDefinition> javaTypes, TypeDefinition type)
{
if (type.IsSubclassOf ("Java.Lang.Object") || type.IsSubclassOf ("Java.Lang.Throwable")) {

// For subclasses of e.g. Android.App.Activity.
javaTypes.Add (type);
} else if (type.IsClass && !type.IsSubclassOf ("System.Exception") && type.ImplementsInterface ("Android.Runtime.IJavaObject")) {
log (
"Type '{0}' implements Android.Runtime.IJavaObject but does not inherit from Java.Lang.Object. It is not supported.",
new [] { type.FullName });
var level = ErrorOnCustomJavaObject ? TraceLevel.Error : TraceLevel.Warning;
var prefix = ErrorOnCustomJavaObject ? "error" : "warning";
Logger (
level,
$"{prefix} XA412: Type `{type.FullName}` implements `Android.Runtime.IJavaObject` but does not inherit `Java.Lang.Object` or `Java.Lang.Throwable`. This is not supported.");
return;
}

if (!type.HasNestedTypes)
return;

foreach (TypeDefinition nested in type.NestedTypes)
AddJavaTypes (javaTypes, nested, log);
AddJavaTypes (javaTypes, nested);
}

public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type)
Expand All @@ -64,6 +76,11 @@ public static bool ShouldSkipJavaCallableWrapperGeneration (TypeDefinition type)

return false;
}

// Returns all types for which we need to generate Java delegate types.
public static List<TypeDefinition> GetJavaTypes (IEnumerable<string> assemblies, IAssemblyResolver resolver, Action<string, object []> log)
{
Action<TraceLevel, string> l = (level, value) => log ("{0}", new string [] { value });
return new JavaTypeScanner (l).GetJavaTypes (assemblies, resolver);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -56,18 +57,27 @@ namespace Java.Interop.Tools.JavaCallableWrappers {
*/
public class TypeNameMapGenerator : IDisposable {

Action<string, object[]> Log;
Action<TraceLevel, string> Log;
List<TypeDefinition> Types;
DirectoryAssemblyResolver Resolver;
JavaTypeScanner Scanner;

[Obsolete ("Use TypeNameMapGenerator(IEnumerable<string>, Action<TraceLevel, string>)")]
public TypeNameMapGenerator (IEnumerable<string> assemblies, Action<string, object []> logMessage)
: this (assemblies, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new[]{value}))
{
if (assemblies == null)
throw new ArgumentNullException ("assemblies");
if (logMessage == null)
throw new ArgumentNullException (nameof (logMessage));
}

Log = logMessage;
public TypeNameMapGenerator (IEnumerable<string> assemblies, Action<TraceLevel, string> logger)
{
if (assemblies == null)
throw new ArgumentNullException ("assemblies");
if (logger == null)
throw new ArgumentNullException (nameof (logger));

Log = logger;
var Assemblies = assemblies.ToList ();
var rp = new ReaderParameters ();

Expand All @@ -83,17 +93,28 @@ public TypeNameMapGenerator (IEnumerable<string> assemblies, Action<string, obje
Resolver.Load (Path.GetFullPath (assembly));
}

Types = JavaTypeScanner.GetJavaTypes (Assemblies, Resolver, logMessage);
Scanner = new JavaTypeScanner (Log) {
ErrorOnCustomJavaObject = false,
};
Types = Scanner.GetJavaTypes (Assemblies, Resolver);
}

[Obsolete ("Use TypeNameMapGenerator(IEnumerable<TypeDefinition>, Action<TraceLevel, string>)")]
public TypeNameMapGenerator (IEnumerable<TypeDefinition> types, Action<string, object[]> logMessage)
: this (types, (TraceLevel level, string value) => logMessage?.Invoke ("{0}", new [] { value }))
{
if (types == null)
throw new ArgumentNullException ("types");
if (logMessage == null)
throw new ArgumentNullException (nameof (logMessage));
}

public TypeNameMapGenerator (IEnumerable<TypeDefinition> types, Action<TraceLevel, string> logger)
{
if (types == null)
throw new ArgumentNullException ("types");
if (logger == null)
throw new ArgumentNullException (nameof (logger));

Log = logMessage;
Log = logger;
Types = types.ToList ();
}

Expand All @@ -112,11 +133,6 @@ protected virtual void Dispose (bool disposing)
Resolver = null;
}

void LogWarning (string format, params object[] args)
{
Log (format, args);
}

public void WriteJavaToManaged (Stream output)
{
if (output == null)
Expand Down Expand Up @@ -160,10 +176,10 @@ Dictionary<string, string> GetTypeMapping (Func<TypeDefinition, bool> skipType,
}
}
foreach (var e in aliases.OrderBy (e => e.Key)) {
LogWarning ("Mapping for type '{0}' is ambiguous between {1} types.", e.Key, e.Value.Count);
LogWarning (" Using: {0}", e.Value.First ());
Log (TraceLevel.Warning, $"Mapping for type '{e.Key}' is ambiguous between {e.Value.Count} types.");
Log (TraceLevel.Warning, $" Using: {e.Value.First ()}");
foreach (var o in e.Value.Skip (1)) {
LogWarning (" Ignoring: {0}", o);
Log (TraceLevel.Info, $" Ignoring: {o}");
}
}
return typeMap.ToDictionary (e => e.Key, e => value (e.Value));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
Expand All @@ -9,6 +10,7 @@
using NUnit.Framework;

using Java.Interop.Tools.Cecil;
using Java.Interop.Tools.Diagnostics;
using Java.Interop.Tools.JavaCallableWrappers;

using Android.App;
Expand All @@ -24,16 +26,25 @@ public class TypeNameMapGeneratorTests
public void ConstructorExceptions ()
{
Action<string, object []> logger = (f, o) => { };
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((string [])null, logger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((TypeDefinition [])null, logger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new string [0], null));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new TypeDefinition [0], null));
Action<string, object []> nullLogger = null;
Action<TraceLevel, string> levelLogger = (l, v) => { };
Action<TraceLevel, string> nullLevelLogger = null;
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((string []) null, levelLogger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((TypeDefinition []) null, levelLogger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new string [0], nullLevelLogger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLevelLogger));
#pragma warning disable 0618
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((string []) null, logger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator ((TypeDefinition []) null, logger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new string [0], nullLogger));
Assert.Throws<ArgumentNullException> (() => new TypeNameMapGenerator (new TypeDefinition [0], nullLogger));
#pragma warning restore 0618
}

[Test]
public void WriteJavaToManaged ()
{
var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logMessage: Console.WriteLine);
var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logger: Diagnostic.CreateConsoleLogger ());
var o = new MemoryStream ();
v.WriteJavaToManaged (o);
var a = ToArray (o);
Expand Down Expand Up @@ -97,7 +108,7 @@ static string GetEntryPart (string value, int length)
[Test]
public void WriteManagedToJava ()
{
var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logMessage: Console.WriteLine);
var v = new TypeNameMapGenerator (SupportDeclarations.GetTestTypeDefinitions (), logger: Diagnostic.CreateConsoleLogger ());
var o = new MemoryStream ();
v.WriteManagedToJava (o);
var a = ToArray (o);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ partial class ExampleBinding {
</member>
<member name="M:SetPeerReference">
<summary>Set the value returned by <c>PeerReference</c>.</summary>
<param name="value">
<param name="reference">
A <see cref="T:Java.Interop.JniObjectReference" /> which contains the
value that future invocations of the
<see cref="P:Java.Interop.IJavaPeerable.PeerReference" />
Expand Down
5 changes: 4 additions & 1 deletion tools/jcw-gen/App.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Threading.Tasks;

using Java.Interop.Tools.Cecil;
using Java.Interop.Tools.Diagnostics;
using Java.Interop.Tools.JavaCallableWrappers;
using Mono.Cecil;
using Mono.Options;
Expand Down Expand Up @@ -41,6 +43,7 @@ public static int Main (string [] args)
"Show this message and exit",
v => help = v != null },
};
var scanner = new JavaTypeScanner (Diagnostic.CreateConsoleLogger ());
try {
var assemblies = options.Parse (args);
if (assemblies.Count == 0 || outputPath == null || help) {
Expand All @@ -60,7 +63,7 @@ public static int Main (string [] args)
resolver.SearchDirectories.Add (Path.GetDirectoryName (assembly));
resolver.Load (assembly);
}
var types = JavaTypeScanner.GetJavaTypes (assemblies, resolver, log: Console.WriteLine)
var types = scanner.GetJavaTypes (assemblies, resolver)
.Where (td => !JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td));
foreach (var type in types) {
GenerateJavaCallableWrapper (type, outputPath);
Expand Down