GWT-Jackson-APT fails on $wnd.window JSON web-worker code for encoding strings - gwt

Finally having gotten GWT-Jackson-APT processors working and properly generating code for my classes, the one remaining hiccup I have is that for some reason gwt-jackson-apt uses the window JSON stringify (& parse) function.
$wnd.window.JSON.stringify(STRING)
The problem is that due to this being on a web-worker, $wnd.window is not defined. Even though JSON.stringify() is available in web-worker, the result is that the code won't run correctly, even though if I modify it to be just JSON.stringify() before uploading it works pefectly.
Is there a clean way to redefine which of these functions gets used in this instance?
What is the best means of going about fixing this so that my web-worker code doesn't try to call the functions that are not available in their context.

The library right now uses the elemental2 version of JSON Global.JSON.stringify
and if we look at the implementation of the JSON in the Global class we will find that it is assigned to the window instance here :
#JsType(isNative = true, name = "window", namespace = JsPackage.GLOBAL)
public class Global {
public static JSONType JSON;
}
when this is used as Global.JSON.stringify(someJsonObject) from GWT java code when compile it will produce $wnd.window.JSON.stringify(someJsonObject) or something very similar.
in order to fix this we need to access the native JSON in a different way that does not link it the current window instance.
one solution to this is to use JsInterop to interface directly with the JSON, something like this
#JsType(isNative = true, namespace = JsPackage.GLOBAL)
public class JSON {
public native static String stringify(Object jsonObj);
}
with this implementation we can use the JSON without the window prefix and when we use it in java like this JSON.stringify(someJsonObject) and notice how we no longer use the one from Global we end up with a generated Js that looks like this $wnd.JSON.stringify(someJsonObject)
i run a small test and implemented this JSON in the jackson-apt lib and switched to use the new implementation instead of using Global.JSON and all tests passed.
to me this looks like a good issue to be reported on the project repository. and i will apply the fix ASAP.

Related

Where to find LinkedHashSet in jsinterop?

I have the following entity in GWT
#JsType(namespace = "my.entities")
public class MyEntity {
private Set<String> texts;
public Set<String> getTexts(){
if(this.texts==null)
this.texts=new LinkedHashSet<String>();
return this.texts;
}
public void setTexts(Set<String> texts){
this.texts=texts;
}
}
When I call myEntityVar.getTexts() in Javascript the returned object is a HashSet. It seems like jsinterop converts the java implementation of HashSet to JavaScript. But how can I create a new HashSet in JavaScript in order to use myEntityVar.setTexts(texts)? I tried an array for the "texts" param, but that doesn't work. So I somehow need to use HashSet in JavaScript.
However, I can't figure out, where to find it.
Any idea?
The short answer is that you can't - but then again, you also can't create a plain HashSet in JS either!
The reason that this works at all is that you've enabled -generateJsInteropExports, and while there is a JsInterop annotation on your MyEntity type, there is also one on java.util.Set (and a few other base JRE types). This allows for your code to return emulated java Sets without issue - any method which is compatible with running in JS is supported.
There are a few downsides:
Compiled size increases somewhat, since even if you don't use a method, it must be compiled in to your app this way, just in case JS uses it
Some methods are not supported - JS doesn't really have method overloading, so toArray() and toArray(T[]) look like the same method in JS. GWT solves this by not supporting the second method at all. (java.util.List has the same issue with remove(T) and remove(int), but it resolves it by renaming remove(int) to removeAtIndex(int) when compiled.)
If you never return these types, you'll probably want to disable this feature entirely - the -excludeJsInteropExports and -includeJsInteropExports flags to the compiler let you control what is exported.
To answer your question more directly, you have a few options that I can see:
Allow the setTexts method to be passed something else from JS, such as a JsArrayLike so that you could let users pass in a plain JS array of strings, or even a JS Set. You could go further and accept Object, and then type-check it to see what was passed in. You could even leave the Set override so it could be called from your own Java if necessary, but mark it as #JsIgnore so that GWT doesn't break when you attempt to export overloaded methods.
Create a factory method somewhere to create the Set implementation you would like your JS users to use. Since add and remove are supported, the calling JS code can build up the set before passing it in. Something like this:
#JsMethod(namespace = "my.Util")
public static <T> LinkedHashSet<T> createSet() {
return new LinkedHashSet<>();
}
Now they can call my.Util.createSet(), append items, and then pass it to your setTexts method.

AS3 targeting controller class variable using string

I'm looking for a way of condensing some of my AS3 code to avoid almost duplicate commands.
The issue is that I have multiple variables with almost the same name e.g. frenchLanguage, englishLanguage, germanLanguage, spanishLanguage
My Controller class contains public static variables (these are accessed across multiple classes) and I need a way to be able to call a few of these variables dynamically. If the variables are in the class you are calling them from you can do this to access them dynamically:
this["spanish"+"Language"]
In AS3 it's not possible to write something like:
Controller.this["spanish"+"Language"]
Is there any way to achieve this? Although everything is working I want to be able to keep my code as minimal as possible.
It is possible to access public static properties of a class this way (assuming the class name is Controller as in your example:
Controller['propertyName']
I'm not sure how this helps to have "minimal code", but this would be a different topic/question, which might need some more details on what you want to achive.
Having said that, I like the approach DodgerThud suggests in the comments of grouping similar values in a (dynamic) Object or Dictonary and give it a proper name.
Keep in mind, that if the string you pass in as the key to the class or dynamic object is created from (textual) user input you should have some checks for the validity of that data, otherwise your programm might crash or expose other fields to the user.
It would make sense to utilize a Dictionary object for a set of variables inherited: it provides a solid logic and it happens to work...
I do not think this is what you are trying to accomplish. I may be wrong.
Classes in AS3 are always wrapped within a package - this is true whether you have compiled from Flash, Flex, Air, or any other...
Don't let Adobe confuse you. This was only done in AS3 to use Java-Based conventions. Regardless, a loosely typed language is often misunderstood, unfortunately. So:
this["SuperObject"]["SubObject"]["ObjectsMethod"][ObjectsMethodsVariable"](args..);
... is technically reliable because the compiler avoids dot notation but at runtime it will collect a lot of unnecessary data to maintain those types of calls.
If efficiency becomes an issue..
Use:
package packages {
import flash.*.*:
class This implements ISpecialInterface {
// Data Objects and Function Model
// for This Class
}
package packages {
import...
class ISpecialInterface extends IEventDispatcher

Passing Java Array into JavaScript (via JSNI) and back out to Java results in null value

Scenario: I have a GWT web application running within a JavaFX WebView/WebEngine. I am able to pass Strings from GWT to JavaScript to JavaFX without any issues.
Problem: When passing an array of custom objects like Data[] in the same fashion, the result on the JavaFX side is null.
An example of what Data looks like:
public class Data extends Serializable
{
char[] name;
int code;
short bar;
}
Here's the code to send the data to JavaScript:
public static native void doNativeStuff(String id, Data[] data) /*-{
$wnd.javaInterface.doStuff(id, data);
}-*/;
I've verified in the debugger that the Java object being passed in is populated with data and looks good.
Now on the JavaFX side, I have the following code to add the javaInterface to the page:
JSObject win = (JSObject) engine.executeScript("window");
win.setMember("javaInterface", new JavaInterface());
I know that this works because I'm using it for other methods that pass only Strings and they work great.
public void doStuff(String id, Data[] data)
{
// Right here, id == "validId" and data == null
if (data != null)
{
... do what is needed ...
}
}
Note that the Data object is defined and accessible on both sides.
From the GWT documentation:
Incoming Java type How it appears to JavaScript code
Java array opaque value that can only be passed back into Java code
I'm not touching it in JavaScript at all and I'm only passing it through from Java->JavaScript->Java, but the final step appears to be what is failing.
I've spent the last few hours scouring Stack Overflow, Google, GWT groups, gwtproject.org, etc. But most all of the examples only show a single argument being passed through and almost none of them show a Java Array being used.
I'd much rather just pass the object through rather than going to->from JSON, but I did give that a try out of desperation. I tried to use GSON but it doesn't work on the GWT client side. I tried to use the GWT AutoBean Framework but my Data object isn't a valid bean (I think because of no default constructor) and I cannot change that at this time.
I'm not using any Long or long values.
I've seen examples like this:
#com.google.gwt.examples.JSNIExample::staticFoo(Ljava/lang/String;)(s);
But from what I can tell that's just for going from JavaScript to GWT over JSNI. I'm trying to go the other way. I also couldn't find an example of this for multiple arguments.
I'm sure that there is just a minor tweak here that I'm missing, but I haven't been able to figure it out just yet. Please let me know if you see something that I'm missing here.
opaque value that can only be passed back into Java code
I think this means you cannot pass Java array into JavaScript code.
Agree with jat. I used to provide support for the similar needs and I had to serialize the objects myself.
And you can pass multiple arguments like this (types of arguments are given just for example):
private native void doJSAction(MyClass handler)/*-{
// do smth in JS
// then call external non-static method
handler.#com.myclient.helper.MyClass::doMyAction(Lcom/google/gwt/core/client/JavaScriptObject;Ljava/lang/String;Lcom/myclient/helper/MyClass;II)(jsNativeSmth, myString, handler, intA, intB);
}-*/;
where doMyAction is something like the following:
void doMyAction(JavaScriptObject jsObject, String s, MyClass instance, int a, int b)
I haven't played with JavaFX, but since it runs in a different VM and knows nothing about the GWT DevMode protocol (for example, a Java object is wrapped in a JS object that basically makes RPC calls to manipulate it), I am pretty sure you are going to have to serialize everything between GWT and JavaFX as Strings and primitives.

PlayFramework instantiate object in current request scope?

I am currently active PlayFramework learner who came from world of PHP.
For example I have a Head block object in my app, which should hold title, charset encoding, meta information, etc. Something similar to Magento blocks, but without XML declaration
package blocks.Page
object Head {
var title: String = "";
}
In Application.index() method I have
blocks.Page.Head.title
Ok(views.html.application.index());
And finally in html template
#import blocks.Page.Head
<title>#Head.title</title>
However, blocks.Page.Head object is defined for entire application scope, not for single request. This object is the same for each request.
What is the right way to do, what I am trying to do? I can create container with all blocks and instantiate it with each request, then just pass to all templates. But I have a feeling that this is wrong way.
Just use usual class instead of object and pass instance to template as parameter.
Like this:
package blocks.Page
case class Head(title: String = "")
Controller:
val head = Head("Blah")
Ok(views.html.application.index(head))
And template will looks like:
#(head: blocks.Page.Head)
...
<title>#head.title</title>
I know the feeling when coming from a request-oriented language like PHP :). However, consider application-wide access as a gift of a VM (in PHP we need to go the extra mile of using some bytecode and data caching tool like APC or eAccellerator).
I would probably create a blockManager class which gives you static access to blocks by name/tag/id from the template: Block.get("MyBlock"). Then you can define and later modify your caching / storing strategy (holding in memory vs. loading from storage) without affecting your templates.

How to access the NUnit test name programmatically?

Is there some global state somewhere that I can access the currently-running test name?
I have tests which output files into a directory and read them back in. I'd like each test to create a directory to play in and then clean up after itself, and I don't want to push that name in (I'd have to make it unique, and then make sure each test keeps it unique; ew). I could use a GUID, but I'd like helper methods to be able to assume "this is the place where test files should be stored" without having to push that GUID around to them. Again, this augers for a global state somewhere.
Basically, I want a call like TestRunner.Current.CurrentTest.Name. Does such a thing exist?
(Assuming c#)
NUnit.Framework.TestContext.CurrentContext.Test.Name
or
NUnit.Framework.TestContext.CurrentContext.Test.FullName
or if you are really lazy and aren't driving your tests with TestCaseSource (thanks #aolszowka):
this.GetType().ToString()
I haven't upgraded to 2.5.7 yet myself, but it includes a TestContext class that seems to provide just what you're looking for: http://www.nunit.org/index.php?p=releaseNotes&r=2.5.7
Assuming one method per Test, in your NUnit code, you can use reflection to get the method name from the stacktrace.
If you write a helper method in your NUnit code called by other methods to do this file logging, you can use this syntax to check for the previous method:
string MethodName = new StackFrame(1).GetMethod().Name;
See the answers to question 44153, "Can you use reflection to find the name of the currently executing method?" for more details.
If we are using TestCaseSource tag then above solutions might not give correct answer
Try using TestContext.CurrentContext.Test.MethodName
Follow the below example
namespace NunitTests
{
public class Class1
{
static List<TestData> Data = new List<TestData>()
{
new TestData()
{
...
}
};
[Test]
[TestCaseSource(nameof(TenMBInstance))]
public void TestCase(TestData value)
{
TestContext.CurrentContext.Test.Name; //TestCase(NunitTests..TestData)
TestContext.CurrentContext.Test.MethodName; //TestCase
}
}
}