Xamarin java binding library compiler error - java

I have a android application (Java) that uses an Android Library.
Everything works fine, but I need to wrap this application into a Xamarin application. So I decided to transform this application into a 2nd Android Library.
I created my Xamarin Android application, and an Android Java Bindings Library project in which I added the two .aar files to the "Jars" folder.
The problems come when I try to compile this binding project. I get a lot of errors like this one :
/.../obj/Release/generated/src/Com.Google.Common.Util.Concurrent.ForwardingListenableFuture.cs(17,17): Error CS0102: The type `Com.Google.Common.Util.Concurrent.ForwardingListenableFutureInvoker' already contains a definition for `id_delegate' (CS0102)
When I open the generated ForwardingListenableFuture.cs file there's this code :
[global::Android.Runtime.Register ("com/google/common/util/concurrent/ForwardingListenableFuture", DoNotGenerateAcw=true)]
internal partial class ForwardingListenableFutureInvoker : ForwardingListenableFuture, global::Com.Google.Common.Util.Concurrent.IListenableFuture {
public ForwardingListenableFutureInvoker (IntPtr handle, JniHandleOwnership transfer) : base (handle, transfer) {}
protected override global::System.Type ThresholdType {
get { return typeof (ForwardingListenableFutureInvoker); }
}
static IntPtr id_delegate;
// Metadata.xml XPath method reference: path="/api/package[#name='com.google.common.util.concurrent']/class[#name='ForwardingListenableFuture']/method[#name='delegate' and count(parameter)=0]"
[Register ("delegate", "()Lcom/google/common/util/concurrent/ListenableFuture;", "GetDelegateHandler")]
protected override global::Com.Google.Common.Util.Concurrent.IListenableFuture Delegate ()
{
if (id_delegate == IntPtr.Zero)
id_delegate = JNIEnv.GetMethodID (class_ref, "delegate", "()Lcom/google/common/util/concurrent/ListenableFuture;");
return global::Java.Lang.Object.GetObject<global::Com.Google.Common.Util.Concurrent.IListenableFuture> (JNIEnv.CallObjectMethod (Handle, id_delegate), JniHandleOwnership.TransferLocalRef);
}
static IntPtr id_delegate;
// Metadata.xml XPath method reference: path="/api/package[#name='com.google.common.util.concurrent']/class[#name='ForwardingFuture']/method[#name='delegate' and count(parameter)=0]"
[Register ("delegate", "()Ljava/util/concurrent/Future;", "GetDelegateHandler")]
protected override global::Java.Util.Concurrent.IFuture Delegate ()
{
if (id_delegate == IntPtr.Zero)
id_delegate = JNIEnv.GetMethodID (class_ref, "delegate", "()Ljava/util/concurrent/Future;");
return global::Java.Lang.Object.GetObject<global::Java.Util.Concurrent.IFuture> (JNIEnv.CallObjectMethod (Handle, id_delegate), JniHandleOwnership.TransferLocalRef);
}
static IntPtr id_delegate;
// Metadata.xml XPath method reference: path="/api/package[#name='com.google.common.collect']/class[#name='ForwardingObject']/method[#name='delegate' and count(parameter)=0]"
[Register ("delegate", "()Ljava/lang/Object;", "GetDelegateHandler")]
protected override global::Java.Lang.Object Delegate ()
{
if (id_delegate == IntPtr.Zero)
id_delegate = JNIEnv.GetMethodID (class_ref, "delegate", "()Ljava/lang/Object;");
return global::Java.Lang.Object.GetObject<global::Java.Lang.Object> (JNIEnv.CallObjectMethod (Handle, id_delegate), JniHandleOwnership.TransferLocalRef);
}
}
Indeed, the "id_delegate" is duplicated..
I also have warnings like this related to the 1st .aar (not the application one) :
/../JARTOXML: Warning J2X9001: Couldn't load class com/company/project/controllers/activities/MenuActivity : java.lang.NoClassDefFoundError: android/support/v4/app/FragmentActivity (J2X9001)

OK I solved the first part of the errors by adding remove-node statements to the Metadata.xml.
For the 2nd part, adding a reference to Xamarin.Android.Support.v4 solved the problem.

Related

How to pass the JSON object in java function using JSNI?

I am learning GWT, I am trying following example in which I have tried to pass the JSON object in java function.
public class HomeController implements EntryPoint {
public void onModuleLoad() {
createTestNativeFunction();
Presenter presenter = new PersenterImpl();
presenter.go(RootPanel.get());
}
public native void createTestNativeFunction()/*-{
parser: function() {
var that = this;
var jsonResult = JSON.parse({id:42,name:'yo'});
return this.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
}
void onParse(jsonResult){
System.out.println(jsonResult);
}
}
}-*/;
}
I am getting following errors:
Tracing compile failure path for type 'com.easylearntutorial.gwt.client.HomeController'
[ERROR] Errors in 'file:/C:/Users/ameen/workspace/Tutorial/src/com/easylearntutorial/gwt/client/HomeController.java'
[ERROR] Line 31: missing ; before statement
void onParse(jsonResult){
--------------------------------^
[ERROR] Hint: Check the inheritance chain from your module; it may not be inheriting a required module or a module may not be adding its source path entries properly
[WARN] Server class 'com.google.gwt.dev.shell.jetty.JDBCUnloader' could not be found in the web app, but was found on the system classpath
[WARN] Adding classpath entry 'file:/C:/Program%20Files/gwt-2.7.0/gwt-dev.jar' to the web app classpath for this session
For additional info see: file:/C:/Program%20Files/gwt-2.7.0/doc/helpInfo/webAppClassPath.html
You really should try to avoid JSNI. You can probably write 99% of your code not using JSNI at all. If you really need it, you should use the new JsInterop instead, documentation still in early stage but you can see this documentation here.
If you need to use JsInterop or JSNI it is usually because you need to wrap a JS lib, so first, try to find if it is already wrapped. If it is not you can always use some other wrapper library to learn how to wrap your JS lib.
OpenLayers JsInterop wrapper https://github.com/TDesjardins/gwt-ol3
OpenLayers JSNI wrapper (deprecated) https://github.com/geosdi/GWT-OpenLayers
Or explore github https://github.com/search?q=topic%3Agwt+topic%3Ajsinterop
System.out.println() is a java function, you are looking for console.log().
The body of the native is JavaScript, not Java.
You are declare you variable jsonResult into your parser: function(), jsonResult only exist into that function. Thats why the system say you that
missing ; before statement
Because you never declare the varieble into createTestNativeFunction().
Plus sjakubowski is right System.out.println() is a java function, you need to use console.log() on JavaScript.
Try this:
public native void createTestNativeFunction(){
var jsonResult = {};
parser: function() {
var that = this;
jsonResult = JSON.parse({id:42,name:'yo'});
return this.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
}
void onParse(jsonResult){
console.log(jsonResult);
}
}
I did the following to solve my errors.
public class HomeController implements EntryPoint {
public void onModuleLoad() {
createTestNativeFunction();
Presenter presenter = new PersenterImpl();
presenter.go(RootPanel.get());
}
// var jsonResult = JSON.parse({id:42,name:'yo'});
public native void createTestNativeFunction()/*-{
var that = this;
$wnd.testFunction = function(jsonResult) {
that.#com.easylearntutorial.gwt.client.HomeController::onParse(Lorg/sgx/jsutil/client/JsObject;)(jsonResult);
};
}-*/;
public void onParse(JsObject jsonResult){
int i =42;
}
}

Migration to wicket 1.5 - resource (path) issue

I got the task to migrate to wicket 1.4 to wicket 1.5. Despite lack of information in migration guide I was somehow able to refactor most issues. Unfortunetly I'm stuck with "resource" - atm I'm getting this error
java.lang.IllegalArgumentException: Argument 'resource' may not be null.
What I understand by that is that something was change and wicket can no longer "get" to my resources. So I used to have (in wicket 1.4) that piece of code that was responsible for creating image and passing it (the method is in class that extends WebPage) :
private void addImageLogo() {
Resource res = new Resource() {
#Override
public IResourceStream getResourceStream() {
String logo = ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH);
return new FileResourceStream(new File(logo));
};
Image logo = new Image("logo", res);
add(logo);
}
Now Resource class no longer exists or I can't find it. While searching internet I was able to change it into this
private void addImageLogo() {
String logoTxt = ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH);
ResourceReference res = new ResourceReference(logoTxt) {
#Override
public IResource getResource() {
return null;
}
};
Image logo = new Image("logo", res);
add(logo);
}
This is responsible for obtaining path (and its working): ConfigurationManager.getInstance().getPathValue(ConfigurationManager.LOGO_FILE_PATH)
Unfortunetly I'm still getting this error that I mentioned above. The method getResource() generated automaticly and I believe this is an issue because I'm retuning null but I have no idea what (or how) should I return.
Since it worked with a IResourceStream in 1.4.x then you can just use org.apache.wicket.request.resource.ResourceStreamResource as a IResource for the Image.
Your first code snippet is not complete so I cannot give you exact replacement code.

Phonegap: Object xx has no method 'exec' at file:///android_asset/www/cordova.js

I developed a tiny module in Android. When using the debug- or run method in Eclipse to test the app on my "real" device, everything works flawlessly.
Using Eclipse (Kepler), PhoneGap 3.1 and Android API 10
But when I sign, export, install and run the app, I see the following error in the debugger once the plugin is called:
file:///android_asset/www/cordova.js: Line 863 : Uncaught TypeError:
Object org.apache.cordova.al#41ae5438 has no method 'exec'
Uncaught TypeError: Object org.apache.cordova.al#41ae2400 has no
method 'exec' at file:///android_asset/www/cordova.js
I am waiting for the deviceready with a deferred object:
var def_deviceready = $.Deferred();
document.addEventListener("deviceready", deviceready, false);
function deviceready(){
def_deviceready.resolve();
}
function dbaccess(query, arg, callback) {
var dbaccess = cordova.require("cordova/plugin/dbaccess");
$.when(def_deviceready).done(dbaccess.getData(query, arg, callback));
};
dbaccess.js:
cordova.define("cordova/plugin/dbaccess", function (require, exports, module) {
var exec = require("cordova/exec");
module.exports = {
getData: function (query, arg, callback) {
exec(callback, function(){ callback('callbackerror')}, "DBAccess", query, arg);
}
};
});
DBAccess.java:
public class DBAccess extends CordovaPlugin {
HashMap<String, SQLiteDatabase> dbmap;
/**
* Constructor.
*/
public DBAccess() {
dbmap = new HashMap<String, SQLiteDatabase>();
}
#Override
public boolean execute(String action, String arg, CallbackContext callbackContext) throws JSONException {
Log.v("info", "This is what we got here: action=\'" + action +"\', arg=\'"+ arg +"\'.");
if (action != null) {
String Result = getData(action, arg);
this.echo(Result, callbackContext);
return true;
}
return false;
}
.....
.....
...and also the config.xml contains:
<feature name="DBAccess">
<param name="android-package" value="com.phonegap.plugin.dbAccess.DBAccess"/>
</feature>
Any help is greatly appreciated...
your script is not able to include dbaccess.js try to add it forcefully in head tag. thats why its not able to exec the method
I checked the whole project again, thanks to the comment of Vicky (I had the dbaccess.js included...).
I found that for some reason, AppLaud configured my App to run with PhoneGap 3.0, but it was being exported with 2.9, and a different config.xml - hence the inclusion for my module wasn't there at all. I could not figure out where or how the different version/xml file was configured/located in.
So I ended up creating a whole new project, copied my relevant files into the according folders, and now I am up and running!

Phonegap: JS call to Java Method works only in 1 case

I am working on a Phonegap Project where i am at the stage of extending the base capabilities of Phonegap with a custom Plugin. The stupid problem i am having is getting the Plugin to react correctly. The Plugin if called with the 'echo' parameter should answer giving back its matched parameter name, the same goes for 'echo2'.
The strange part:
'echo' returns the expected answer (it executes the success callback) whereas the 'echo2' variant returns the error callback. Seriously running out of ideas...
The JS Definitions: Identical functions (only the 4th Parameter is different)
window.echo = function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to echo.');
}, 'Echo', 'echo', [str]);
};
window.sync = function(str, callback) {
cordova.exec(callback, function(err) {
callback('Nothing to echo.');
}, 'Echo', 'echo2', [str]);
};
The JS Calls on these functions:
echo('Echo String', function(echoValue) {
alert(echoValue);
});
sync('Sync String', function(echoValue) {
alert(echoValue);
});
Java Class:
public class Echo extends CordovaPlugin {
#Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
switch(action) {
case "echo": String message = args.getString(0);
this.echo("Call on: Echo.echo()" + message, callbackContext);
return true;
case "echo2": String message = args.getString(0);
this.echo("Call on: Echo.echo2()" + message, callbackContext);
return true;
}
return false;
}
private void echo(String message, CallbackContext callbackContext) {
if (message != null && message.length() > 0) {
callbackContext.success(message);
} else {
callbackContext.error("Expected one non-empty string argument.");
}
}
}
To all those having a similar problem, here is some information on why this did not work:
Firstly: The Code works fine - the problem doesn't lie here.
Where's the fault?
When i asked the question, the Java Class was named Echo which worked when the class method was being called. Trying to call any other method fails because the
Phonegap Build Service does not allow direct includes of plugins
BUT in my case it still partially worked because the Java Class Echo happens to be a standard Plugin that Phonegap Build included for me.
This Echo Plugin being included by Phonegap Build happens to have a method echo which resulted in a success callback, obviously.
After further reading:
A tool called plugman (also developed by Adobe) handles the custom plugin implementation by adding the created plugin to the phonegap project ... i am still testing and learning this, the official information (and only information i found) is available here:
► Leads to the deprecated pluginstall tool
► Plugman Tool Repo - GitHub

JNAerator - using interfaces generated by typedef

I'm trying to use a generated interface by JNAerator from a typedef instruction, but I can't find a way to do that:
The function in the .h file is:
MyClass::Initialize(LPCWSTR path);
The header file also includes the original typedef instruction:
typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;
JNAerator generates:
Method:
public native int Initialize(LPCWSTR path);
The interface:
/// Undefined type
/// Undefined type
public static interface LPCWSTR {
};
And the classes:
/// C type : WCHAR*
public Pointer<Short > LPCWSTR() {
try {
return (Pointer<Short >)BridJ.getNativeLibrary("dlls").getSymbolPointer("LPCWSTR").as(DefaultParameterizedType.paramType(Pointer.class, Short.class)).get();
}catch (Throwable $ex$) {
throw new RuntimeException($ex$);
}
}
/// C type : WCHAR*
public MainLibrary LPCWSTR(Pointer<Short > LPCWSTR) {
try {
{
BridJ.getNativeLibrary("dlls").getSymbolPointer("LPCWSTR").as(DefaultParameterizedType.paramType(Pointer.class, Short.class)).set(LPCWSTR);
return this;
}
}catch (Throwable $ex$) {
throw new RuntimeException($ex$);
}
}
The problem is, I don't know how to instantiate an object LPCWSTR using Pointer and the LPCWSTR interface, using a String, so that I can pass it to the Initialize method.
How can I do this?
UPDATE:
I modified the .h file to use wchar_t*:
MyClass::Initialize(wchar_t* path)
JNAerator generated the method like this:
public native int Initialize(Pointer<Character > path);
So I called it like this:
MyClass factory = new MyClass();
Pointer<Character> path = org.bridj.Pointer.pointerToWideCString("dlls");
factory.Initialize(path);
The problem is that I get the following exception:
java.lang.UnsatisfiedLinkError: main.MyClass.Initialize(Lorg/bridj/Pointer;)I
at this line:
factory.Initialize(path);
What am I doing wrong?
The UnsatisfiedLinkError indicates that your native Initialize method was not bound by BridJ.
This binding is done by CPPObject's constructor (I assume you got a JNAerated MyClass class that inherits from it), and any failure to bind should result in error logs in your console (in any case, you can increase the logs verbosity with BRIDJ_VERBOSE=1 environment variable).
Also, please note that your MyClass should have a #Library("mylibrary") annotation to let it know where to find the appropriate library (.dll, .so or .dylib), or should be an inner class of a class with such an annotation. This is normally the case of JNAerated classes, but if it's not, please report a bug in NativeLibs4Java's tracker.
I was having this problem too. zOlive’s response sent me down the right path. I changed the JNAerator library option to match my DLL name (e.g. -library MyLib MyLib.dll MyLib.h). That fixed it for me. There is more info about the library option here.

Categories