Xamarin mapsforge binding generic collections issue - xamarin.android

I am trying to bind mapsforge JAR. In Overlay class of this library there are many generic collections. Overlay class implements Java.Util.IList and
Interface Java.Util.IList want realization like this
"Mapsforge.Android.Maps.OverlayNs.OverlayList" does not implement "Java.Util.IList.AddAll(int, System.Collections.ICollection)" 8 23 MapForgeDroid
So, i created Metadata.xml Mapsforge.Android Mapsforge.Android.Maps.OverlayNs
<!-- Return Java.Lang.Object in OverlayManager so that we match interface. -->
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayCircleOverlay']/method[#name='createCircle']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayItemizedOverlay']/method[#name='createItem']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayWayOverlay']/method[#name='createWay']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayItemizedOverlay']/method[#name='getThreadName']" name="visibility">protected</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayCircleOverlay']/method[#name='getThreadName']" name="visibility">protected</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='ArrayWayOverlay']/method[#name='getThreadName']" name="visibility">protected</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='add' and count(parameter)=1]/parameter[#name='p0']" name="managedType">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='add' and count(parameter)=2]/parameter[#name='p1']" name="managedType">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='retainAll']/parameter[#name='p0']" name="managedType">System.Collections.ICollection</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='removeAll']/parameter[#name='p0']" name="managedType">System.Collections.ICollection</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='containsAll']/parameter[#name='p0']" name="managedType">System.Collections.ICollection</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='addAll' and count(parameter)=1]/parameter[#name='p0']" name="managedType">System.Collections.ICollection</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='addAll' and count(parameter)=2]/parameter[#name='p1']" name="managedType">System.Collections.ICollection</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='set']/parameter[#name='p1']" name="managedType">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='set']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='get']" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='remove' and count(parameter)=1 and parameter[1][#type='int']]" name="managedReturn">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']/method[#name='subList']" name="managedReturn">System.Collections.IList</attr>
<attr path="/api/package[#name='org.mapsforge.android.maps.mapgenerator']/class[#name='MapGeneratorJob']/method[#name='compareTo']/parameter[#name='p0']" name="managedType">Java.Lang.Object</attr>
<attr path="/api/package[#name='org.mapsforge.core']/class[#name='GeoPoint']/method[#name='compareTo']/parameter[#name='p0']" name="managedType">Java.Lang.Object</attr>
</metadata>
But many new erros appeared - all methods wants generic collections:
error CS1502: The best overloaded method match for "Mapsforge.Android.Maps.OverlayNs.OverlayList.AddAll(int, System.Collections.ICollection)" has some invalid arguments
error CS1503: Argument "2": cannot convert from "System.Collections.Generic.ICollection<Mapsforge.Android.Maps.OverlayNs.Overlay>" to "System.Collections.ICollection"
error CS1502: The best overloaded method match for "Mapsforge.Android.Maps.OverlayNs.OverlayList.AddAll(System.Collections.ICollection)" has some invalid arguments
error CS1503: Argument "1": cannot convert from "System.Collections.Generic.ICollection<Mapsforge.Android.Maps.OverlayNs.Overlay>" to "System.Collections.ICollection"
error CS1502: The best overloaded method match for "Mapsforge.Android.Maps.OverlayNs.OverlayList.ContainsAll(System.Collections.ICollection)" has some invalid arguments
error CS1503: Argument "1": cannot convert from "System.Collections.Generic.ICollection<object>" to "System.Collections.ICollection"
error CS1502: The best overloaded method match for "Mapsforge.Android.Maps.OverlayNs.OverlayList.RemoveAll(System.Collections.ICollection)" has some invalid arguments
error CS1503: Argument "1": cannot convert from "System.Collections.Generic.ICollection<object>" to "System.Collections.ICollection"
error CS1502: The best overloaded method match for "Mapsforge.Android.Maps.OverlayNs.OverlayList.RetainAll(System.Collections.ICollection)" has some invalid arguments
error CS1503: Argument "1": cannot convert from "System.Collections.Generic.ICollection<object>" to "System.Collections.ICollection"
error CS0266: Cannot implicitly convert type "System.Collections.Generic.IList<Mapsforge.Android.Maps.OverlayNs.Overlay>" to "System.Collections.IList".
error CS0266: Cannot implicitly convert type "System.Collections.Generic.IList<Mapsforge.Android.Maps.OverlayNs.Overlay>" to "System.Collections.IList".
If i change type from System.Collections.ICollection to System.Collections.Generic.ICollection it generate "does not implement" error. What can i do to workaround this problem?

I fell into the same problem of you during my last Xamarin android project, because I had to bind a JAR that make massive use of Java generics.
First of all you can read the following bug (https://bugzilla.xamarin.com/show_bug.cgi?id=19740) that has been open on bugzilla, relative to the binding problem of Java generics.
In that thread there are explained the limits of the Android Callable Wrappers generator, and also the possible solution that you can implement if you need to bind a Jar that use Java generics.
In my opinion that solution is suitable only if your Jar doesn't make a massive use of generics, this means that if you only have one generic class maybe this is the best solution.
To overcome the original problem I have used another approach, because the Jar that I was binding use several generic classes that I need to call inside my Xamarin project. My approach was simply to work on the native side. This means include your Jar inside a Java Project extending the generic class with a specific type.
NOTE:
Requirements for this implementation is that you have to know the generic types that you will need.
Just to be clear, suppose that your original Jar, called genericJar contains a generic class called Event<T>, and suppose that you know that T could be of type "A" or type "B".
What you need to do is to create a Java project that include you Jar, and then inside this project create the following classes:
public class EventA extends Event <A> {...}
public class EventB extends Event <B> {...}
Once you have done this you create a Jar from this java project, and use this as the starting Jar for your Xamarin Android project.
The binding project will try to bind the original Event<T> class, giving you the original error. To avoid this you have to work on the Metadata.xml inside your binding project.
Inside Metadata.xml you have to add the following line to tell Xamarin to avoid binding the generic class:
<remove-node path="/api/package[#name='com.originalJar.event']" />
Once you have done this you will be able to generate the DLL that you need for your Xamarin project, where you will be able to use EventA and EventB classes, avoiding generics problem.
I have found that this is the best approach at the moment to bind Java generic classes, let me know if this could help you to solve your problem ;)

I found the solution (and it works!!!)
First: remove all of the OverlayList nodes and add this:
<remove-node path="/api/package[#name='org.mapsforge.android.maps.overlay']/class[#name='OverlayList']" />
This removes the ability to directly use the OverlayList, but allows the library to work.

Related

gdbus type naming for structs

With gdbus codegen, a struct/object is defined as a complete type in the xml like below
<method name="GetInfo">
<arg direction="out" type="(sib)" name="info"/>
</method>
However, if the same struct is used at multiple places, repeating the type definition is a bit painful, especially when the signature changes later on.
<method name="GetInfoList">
<arg direction="out" type="a(sib)" name="info_list"/>
</method>
So, is there a way to define an alias or a something for structs that we don't have to maintain the same thing at multiple places? Oh, and using Qt bindings is not an option in this case unfortunately.
Regards,
So, is there a way to define an alias or a something for structs that we don't have to maintain the same thing at multiple places?
No, there is not. That’s one of the disadvantages of using gdbus-codegen. If you want to define a struct for each of the D-Bus types in your API, you need to implement your service/client manually, without gdbus-codegen, using functions like g_dbus_connection_register_object().

F# type inferrence issue

I have experienced the following problem while writing a test. Please find a picture bellow.
If I create validateGameExistance function in the unit test project then it works fine.
How could it be solved?
It is hard to give a definite answer (based just on the screenshot), but you can get this kind of error when some of the types involved in the type error are defined in multiple places (so, the type name would look the same, but they would actually be different types in different assemblies).
For example, if the Result<T> type is defined in multiple projects and the function you're calling returns one of them, but your annotation is referring to another one.

Is it possible to use Ninject Named Bindings using ninject.extensions.xml

I have a very simple problem of DI, and wanted to know if there is a way to solve it using Ninject (or any other DI helper).
I have a Data Access interface that is implemented by several Data Sources providers, like DB, Sharepoint, CRM, etc.
I want to use Ninject to get a specific instance of the interface, based on a parameter that contains a code representing one of this implementations.
So far I know that I can do that by using named bindings , but I couldn't find a way to do the same by xml config file (Ninject.extensions.xml).
Ninject extensions xml provides a way to solve single mappings:
<module name="SomeModule">
<bind service="Game.IWeapon" to="Game.Sword"/>
<bind service="Game.IWarrior" toProvider="Game.SamuraiProvider"/>
</module>
I'd like to do a config like that, but using multiple mappings for the same interface, using a name, a code or the like.
TIA,
Milton
Just add a name property
<bind service="Game.IWeapon" to="Game.Sword" name="sword"/>
<bind service="Game.IWeapon" to="Game.Dagger" name="dagger"/>

Ant The best way of excluding sensitive class files

Ant Best way of excluding sensitive class files
After a few trials, I found that if the class is mentioned in the code javac will ignore the exclude list and still compile the class if it can find it rather than throwing an error.
I would prefer an error was thrown than it compiling with my sensitive class.
I also noticed that conditional compilation is ignored so if the code is like
static final boolean DEBUG = false;
//interface which TestSensitive & NormalClass implement
ITestWrapper testWrapper = null;
if(DEBUG){
testWrapper = new TestSensitive();
}else{
testWrapper = new NormalClass();
}
testWrapper.print_Msg();
In build.xml in javac
<src path="${source.absolute.dir}" />
<exclude name="**/Test*.java" />
<src path="${gen.absolute.dir}" />
TestSensitive is still being compiled even though the call to testWrapper = new TestSensitive() should be ignored by the conditional compile.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.21
http://www.javapractices.com/topic/TopicAction.do?Id=64
At the moment the only way I think can achieve what I want is to copy out the TestSensitive class and copy in a dummy hollow TestSensitive class. Is there a better way of doing this.
Let me answer to the non-ant part of the question (anyway, till you solve it you can't progress any further):
Seems you're contradicting youself, your DEBUG is true, so why do you wonder about TestSensitive? It's the if branch which is chosen.
However I believe for references to other classes, you need to have these during compilation on your classpath. I believe you can't prevent that this way.
However there are ways to achieve the behaviour expected. For example:
via reflection - you would load class using it's name and instantiate/use it later, or
as you already have common interface ITestWrapper:
and use some IOC (inversion of control) concept using framework like Spring or
via some self registration of classes (like listeners)

Fully qualified name, unqualified name with import declaration resolve differently

This works
open System
let f = Action(fun () -> Unchecked.defaultof<_>)
But this
let f = System.Action(fun () -> Unchecked.defaultof<_>)
produces the compilation error
Multiple types exist called 'Action', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'Action<,,_,,,_,,,_>'.
I know I can fix it by adding a type parameter placeholder (System.Action<_>(...)), but any idea why they behave differently?
EDIT
Found this in the spec, section 14.1.9:
When a module or namespace declaration group F is opened, items are added to the name environment as follows:
Add the type to the TypeNames table. If the type has a CLI-mangled generic name such as List'1 then an entry is added under both List and List'1.
Is this behavior replicated for fully-qualified types (with omitted type parameters)? It doesn't appear so.
I agree with #James that this is related to the bug submitted on Connect, but I think it is a slightly different case. Anyway, I think this is not the intended behaviour. Could you report it to fsbugs at microsoft dot com?
Anyway - I did some debugging and here is what I found so far:
It seems that the compiler uses different code paths to resolve the name Action and the name System.Action. When resolving the other, it searches all loaded modules (i.e. assemblies) for a type named System.Action (see ResolveLongIndentAsModuleOrNamespaceThen function in the nameres.fs file of the open-source release).
This finds the two definitions of Action (one in mscorlib and another in System.Core). I think the issue comes from the fact that the name resolution simply iterates over the results - it finds the first one (from System.Core), which doesn't have a usable overload (because it ranges from Action<_,_,_,_,_> to a version with about 15 type parameters). After finding this type, it reports an error without even looking whether there is another type (in another assembly) that could be used.
If you don't reference system assemblies, then the F# compiler resolves the overload just fine. Running the compiler without parameters references the default assembly set, so this doesn't work:
fsc test.fs
but if I add the --noframework flag, then it compiles without issues:
fsc --noframework test.fs

Resources