unable to resolve method in class - javascript

1.is it possible to call the native method in the gwt into the other native method ?
this is the method i am calling from the VectorSource.java into Map.java
https://github.com/VOL3/v-ol3/blob/master/gwt-ol3/src/main/java/org/vaadin/gwtol3/client/source/VectorSource.java
public final native JsArray<Feature> getFeatures()/*-{
return this.getFeatures();
}-*/;
and i created a native method in Map.java class and getting the Features and i want to return these feature values to addOnPostRenderListener method below are the changes in the Map.java class
public native final Feature getFeatures(VectorSource sourceFeature)/*-{
var features=sourceFeature.#org.vaadin.gwtol3.client.source.VectorSource::getFeatures();
return features;
}-*/;
public native final void addOnPostRenderListener(OnPostRenderListener listener)/*-{
if(!this.__registered){
var that=this;
that.once('postrender',function(){
var feature=that.#org.vaadin.gwtol3.client.Map::getFeatures(vectorSource);
if(feature!=null){
var coordinate=feature.getGeometry().getCoordinate();
if(coordinates!=null){
var MapEvent={Pixel:that.getPixelFromCoordinate(that.__transformInputCoordinate(coordinates))};
that.__notifyPostRenderListeners(MapEvent);
}
}})
this.__postRenderListeners.push(listener);
}
}-*/;
the remaining code remains the same as shown in the below link
https://github.com/VOL3/v-ol3/blob/master/gwt-ol3/src/main/java/org/vaadin/gwtol3/client/Map.java
at the below code i am getting the error,as Expected a valid parameter type signature in JSNI method reference these lines of code is in the addOnPostRenderListener method
var feature=that.#org.vaadin.gwtol3.client.Map::getFeatures(vectorSource);
my target is to call the method getFeatures() from VectorSource.java class into the Map.java class and send the values to the other native method which is addOnPostRenderListener method.
Interface
public interface OnPostRenderListener {
public void onRender(MapEvent posEvent);
}
MapEvent
public class MapEvent extends JavaScriptObject {
protected MapEvent() {
}
public static final native Feature create()/*-{
return new $wnd.ol.Feature();
}-*/;
public native final Geometry getGeometry()-{
return this.getGeometry();
}-;*/
public native final Geometry getGeometry()/*-{
return this.geometry;
}-*/;
public native final Coordinate getCoordinate()/*-{
return this.coordinate;
}-*/;
public native final Pixel getPixel()/*-{
return this.Pixel;
}-*/;
//written code not used
public native final Map getPixelFromCoordinate(Coordinate coord)/*-{
return this.getPixelFromCoordinate(coord);
}-*/;
}

You need to pass your VectorSource sourceFeature parameter too. You are missing it in that.#org.vaadin.gwtol3.client.Map::getFeatures(Lcom/google/gwt/core/client/Source;);.
One way to do this, would be add it to your
addOnPostRenderListener(OnPostRenderListener listener)
e.g. addOnPostRenderListener(OnPostRenderListener listener, VectorSource vectorSource)
and then to access it like this:
var feature=that.#org.vaadin.gwtol3.client.Map::getFeatures(vectorSource);
Although I would recommend to completely drop JSNI and use the much better JsInterop. There is an OL-implementation using JsInterop too. Take a look here

Related

How to pass class-name as arguments and invoke common static methods in GWT jsni?

I have lot of enum class and all having one common method. I want to invoke that common method and return dynamically using GWT jsni method.
Let say I have following enum classes in different packages.
package A;
enum WidgetType{
TEXT_BOX("A"),SVG("B");
String type;
WidgetType(String type){
this.type = type;
}
public static WidgetType getDescriptiveValue( String type ){
for(WidgetType widgetType : WidgetType.values()){
if(widgetType.type.equalsIgnoreCase(type) ) return widgetType;
}
return null;
}
}
package B;
enum MessageType{
INFO("I"),WARN("W"),ERROR("E");
String type;
MessageType(String type){
this.type = type;
}
public static MessageType getDescriptiveValue( String type ){
for(MessageType messageType : MessageType.values()){
if(messageType.type.equalsIgnoreCase(type) ) return messageType;
}
return null;
}
}
Somewhat I will get enum full qualified names in string like [A.WidgetType,B.MessageType].
Based on this value I want to invoke enum class getDescriptiveValue method using JSNI.
So How to achieve this in GWT jsni.
When I try to pass class name as arguments like below I am getting compile time error.
Approach 1:
native void enumValue(String enumClass,String value) /*-{
console.log($entry(#enumClass::getDescriptiveValue(Ljava/lang/String;)(value)) );
}-*/;
Approach 2:
native void enumValue(String enumClass,String value) /*-{
console.log(#enumClass::getDescriptiveValue(Ljava/lang/String;)(value));
}-*/;
I don't know is there any way to use Java Reflection in GWT client side?
Please suggest me how to achieve this?
Put simply, this will not work - the JSNI syntax for java types/members is only a way to write plain code which will be evaluated at compile time into the JS equivalent of the member you are describing. You cannot simply turn a string into a class literal.
Instead, depending on how many enums you may wish to support in this way, consider constructing a Map<String, Map<String, Object>> of the enum types and param types you are looking for. This will require either manual code to list each enum type, or code generation to do this for you, and has the added advantage of not including JSNI.
Consider a type like this, which requires that each Enum you give it implements some HasType interface, which ensures that all have a getType() method, so they can be reflected on in the same way.
public class EnumLookup {
private final Map<String, Map<String, Object>> enumCache = new HashMap<>();
/** Helper that you can call internally or externally to build up the cache */
public <E extends HasType> void register(Class<E> type, E[] values) {
Map<String, Object> values = enumCache.computeIfAbsent(type.toString(), classname -> new HashMap<>());
for (E enumValue : values) {
values.put(enumValue.getType().toLowerCase(), enumValue);
}
}
/** And now the method you are trying to write */
public <E extends HasType> void enumValue(String enumClass, String value) {
// use of toLowerCase here and above ensures that type strings will match like
// in your original java
return (E) enumCache.get(enumClass).get(value.toLowerCase());
}
}
and then populate the cache somewhere
EnumCache cache = new EnumCache();
cache.register(WidgetType.class, WidgetType.values());
cache.register(MessageType.class, MessageType.values());
//...
Another way would be for the map to contain a Function<String, Object>, and use that to point at the getDescriptiveValue via a method reference. Then the registration would look like this:
cache.register(WidgetType.class, WidgetType::getDescriptiveValue);
cache.register(MessageType.class, MessageType::getDescriptiveValue);

How to deal with javascript multi-object function with WebView component in android?

Now I need to use webview component to load a HTML page and deal with component function.
The content in HTML page is ,
you can see there is a multi-object (webkit.messageHandlers.adClicked), how could I to use webView.addJavascriptInterface() function to deal with it?
I know how to deal with single object, but I don't know how to deal with multi-object?
I use following code, but it does not work:
enter code here
webView.addJavascriptInterface(this, "webkit");
webView.addJavascriptInterface(this, "messageHandlers");
webView.addJavascriptInterface(this, "adClicked");
webView.addJavascriptInterface(this, "webkit.messageHandlers.thepaperNewsClicked");
#android.webkit.JavascriptInterface
public void postMessage(final String str) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(getContext(), "param:" + str, Toast.LENGTH_SHORT).show();
}
});
From android API document :
void addJavascriptInterface (Object object, String name)
The parameter "name" is used to let javascript to call from android, so you can just deal with single object; you can create one class and put
in functions which can been called for javascript, and give one name for javascript to call.
you can see what they do in this post:
https://stackoverflow.com/a/24060790/8355528
Reference site:
https://developer.android.com/reference/android/webkit/WebView.html

What is the use of overriding hasMember() inside JSObject, AbstractJSObject?

I understand that this helper method can be called from a Java code to check if your Java/JS Object has a property you are looking for
but i would like to know if this is called by the Nashorn Engine while we use this JSObject/AbstractJSObject implementation in a JavaScript code.
I am aware of the fact that doing a . inside JavaScript will in turn invoke the Java method .getMember()
If "in" operator in used in JavaScript (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in) on a JSObject instance, Nashorn will call hasMember method on that JSObject.
Example code:
import javax.script.*;
import jdk.nashorn.api.scripting.*;
public class Main {
public static void main(String[] args) throws Exception {
ScriptEngineManager m = new ScriptEngineManager();
ScriptEngine e = m.getEngineByName("nashorn");
e.put("obj", new AbstractJSObject() {
#Override
public boolean hasMember(String name) {
System.out.println("hasMember called for " + name);
return false;
}
});
// in operator triggers hasMember call on JSObject instance
e.eval("if ('foo' in obj) print('yes')");
}
}
The output from the above program looks like:
hasMember called for foo

Passing Android webview JS interface method as callback function

I have the following android code:
private class MyJavaInterface {
#android.webkit.JavascriptInterface
public void call(String number) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + number));
startActivity(intent);
}
}
...
mWebView.addJavascriptInterface(new MyJavaInterface(), "MyInterface");
This JS code works correctly:
MyInterface.call(number);
And this does not:
var call = MyInterface.call;
call(number);
What am I doing wrong?
This JS code works correctly:
MyInterface.call(number);
Yes, this will work fine because Android will automatically find the class and the only public methods that are annotated.
For your case
MyInterface.call(number) -> new MyJavaInterface().call(number)
But the Second one will not work,
MyInterface.call -> new MyJavaInterface().call - there is no public variable in your class and also there is no support for variable in addJavascriptInterface
Note : Refer
For applications targeted to API level JELLY_BEAN_MR1 and above, only
public methods that are annotated with JavascriptInterface can be
accessed from JavaScript. For applications targeted to API level
JELLY_BEAN or below, all public methods (including the inherited ones)
can be accessed

Monodroid JavaScript Interface

Monodroid does not yet natively support JavaScriptInterface with WebView.
I'm looking for an example .java file that can be used with this workaround.
IntPtr JavaScriptInterface_Class = JNIEnv.FindClass ("the/package/for/JavaScriptInterface");
IntPtr JavaScriptInterface_ctor = JNIEnv.GetMethodID (JavaScriptInterface_Class, "<init>", "()V");
IntPtr instance = JNIEnv.NewObject (JavaScriptInterface_Class, JavaScriptInterface_ctor);
appView.AddJavascriptInterface (new Java.Lang.Object (instance), "Android");
You could use a custom .java such as:
// TODO: use an actually valid package name. :-)
package the.package.for;
public class JavaScriptInterface {
// The JNI in the original question uses a default constructor.
// Either provide one explicitly or use the implicit one...
public JavaScriptInterface ()
{
}
// TODO: add any methods you want invokable from JavaScript here.
}
Don't forget to set the Build action for your .java file to to AndroidJavaSource.
I know that this thread is already a bit old. But i found this when was looking for the same and here is the solution how you can use c# methods
public class AndroidInterface : Java.Lang.Object
{
[Export]
public void Save(string text)
{
}
}
AndroidInterface androidInterace = new AndroidInterface();
webView.AddJavascriptInterface(androidInterface, "Android");

Categories

Resources