Bug 8754 - Java.Interop.ExportAttribute should be usable on constructors
Summary: Java.Interop.ExportAttribute should be usable on constructors
Status: ASSIGNED
Alias: None
Product: Android
Classification: Xamarin
Component: Bindings ()
Version: 4.5.x
Hardware: PC Mac OS
: Normal enhancement
Target Milestone: master
Assignee: Atsushi Eno
URL:
Depends on:
Blocks:
 
Reported: 2012-12-04 17:22 UTC by Jonathan Pryor
Modified: 2016-09-21 11:57 UTC (History)
4 users (show)

Tags: XATriaged
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report for Bug 8754 on Developer Community or GitHub if you have new information to add and do not yet see a matching new report.

If the latest results still closely match this report, you can use the original description:

  • Export the original title and description: Developer Community HTML or GitHub Markdown
  • Copy the title and description into the new report. Adjust them to be up-to-date if needed.
  • Add your new information.

In special cases on GitHub you might also want the comments: GitHub Markdown with public comments

Related Links:
Status:
ASSIGNED

Description Jonathan Pryor 2012-12-04 17:22:29 UTC
Context: http://forums.xamarin.com/discussion/500/inheriting-from-fileinputstream

It's not possible to subclass Java.IO.FileInputStream because the constructors may throw an exception, which requires that the ACW declare them (via a Java `throws` clause) or catch the exceptions.

If Java.Interop.ExportAttribute were usable on constructors, we could appease the Java compiler:

	partial class DeviceInputStream : Java.IO.FileInputStream
	{
		[Java.Interop.Export (Throws = new[]{
				typeof (Java.IO.FileNotFoundException)})]
		public DeviceInputStream(Java.IO.FileDescriptor fd)
			: base(fd)
		{
			// ...
		}
	}

The resulting ACW would contain:

	public class DeviceInputStream
		extends java.io.FileInputStream
		implements
			mono.android.IGCUserPeer
	{
		public DeviceInputStream (java.io.File p0) throws java.io.FileNotFoundException
		{
			// ...
		}
		// ...
	}
Comment 10 Atsushi Eno 2013-07-09 22:46:49 UTC
I have applied the change to get FileInputStream derivation working without Export attribute, based on some (private) discussion: now we have "throws Throwable" on all generated constructors.

We still keep this bug open and discuss other uses of exported constructors.
Comment 11 Jonathan Pryor 2013-07-09 22:49:49 UTC
I think all methods should likewise get `throws Throwable` unless they're [Export]ed and have their own Throwable declaration.
Comment 13 Atsushi Eno 2013-07-09 23:12:30 UTC
I believe we don't really need to add throws Throwable on methods because we throw RuntimeException.
Comment 15 Jonathan Pryor 2013-07-09 23:17:51 UTC
> I believe we don't really need to add throws Throwable on methods because we
> throw RuntimeException.

Eh?

Consider:

    // C#
    [Export]
    public static void Foo()
    {
        throw new Java.Lang.Exception ("die!");
    }

Generated ACW:

    // Java
    public static void Foo() // no `throws`!
    {
        n_Foo();
    }
    static extern void n_Foo();

So if/when Java calls the Foo() method, a java.lang.Exception instance will be thrown, in complete "defiance" of the `throws` clause. (Which kinda makes sense, as `throws` is a compiler-aid, and means nothing at runtime.)

There is no magic wrapping in RuntimeException, unless it's an exception type that _doesn't_ inherit Java.Lang.Throwable, in which case we wrap it in java.lang.Throwable, not RuntimeException (see Java.Lang.Throwable.FromException(Exception)).

Consequently, I think it would be more "intellectually honest" if all methods had `throws Throwable`, as they truly can throw anything.
Comment 17 Atsushi Eno 2013-07-09 23:34:16 UTC
Adding "throws" declaration part is only about having Java compiler compile the sources.

"private static native void n_Foo()" may throw Throwable in the implementation, but for javac it does not trigger any requirement to add "throws" declaration part. You *can* add throws declaration, but that makes no sense because those who reads the generated java sources should notice that native methods() can throw anything and it cannot be retrieved by its declaration.
Comment 20 Jonathan Pryor 2013-07-10 11:19:13 UTC
> Adding "throws" declaration part is only about having Java compiler compile the sources.
> 
> "private static native void n_Foo()" may throw Throwable in the implementation,
> but for javac it does not trigger any requirement to add "throws" declaration
> part.

Ah, but it _can_, if we squint "just right". Case in point, Bug #382 + Java serialization. Java Serialization requires that the readObject() and writeObject() methods have `throws` clauses, which is why we needed the ExportAttribute.Throws property.

If we generated `throws Throwable` on all method declarations, we'd simplify this usecase, allowing:

    [Export]
    private void writeObject(Java.IO.ObjectOutputStream destination)
    {/*...*/}

Meaning a ~one-line ACW generator change would simplify this (seldom used) usecase.

Note that I'm not saying that the `n_`-prefixed method should get `throws`, but the "real" method. For example, writeObject() should get `throws`, not n_writeObject().
Comment 34 Atsushi Eno 2013-07-17 03:06:55 UTC
New ExportAttribute support on constructor with SuperArgumentsString property is applied. [master a6c3497] SuperArgumentsString, when explicitly specified, is directly embedded to call to super() in the corresponding Java constructor, enabling different set of parameters from that of the corresponding managed constructor.

Usage example:

    public class ExportedConstructorTest : Android.Views.View
    {
        const string monoAppContext = "(android.content.Context) Class.forName
(\"mono.android.app.Application\").getField (\"Context\").get (null)";

        [Export (SuperArgumentsString = monoAppContext)]
        public ExportedConstructorTest ()
            : base (Application.Context)
        {
        }

        [Export (SuperArgumentsString = monoAppContext)]
        public ExportedConstructorTest (IAttributeSet attrs)
            : base (Application.Context, attrs)
        {
        }
    }

We keep this bug open for further possible utility properties on ExportAttribute.