What causes GWT to output: <SomethingNotNull>.nullMethod()? - gwt

I have my own emulation of java.util.Timer (and quite a lot of other stuff missing in GWT). I have even a JUnit test proving it works in the browser.
I've just tried to convert some third-party library to GWT, which needed a Timer, and in some part of it, I call:
SystemUtils.getTimer().scheduleAtFixedRate(timerTask, value, value);
But the GWT compiler turns getTimer().scheduleAtFixedRate() to:
getTimer().nullMethod()
SystemUtils.getTimer() is a static method. I have googled for nullMethod(), but most hits are about:
null.nullMethod();
That doesn't apply to me. What could be going wrong, and what can I do to fix it?
[EDIT] Actually, the java.util.Timer emulation itself works, but it seems that (atm?) SystemUtils.getTimer() returns "undefined". Could that be the reason? Since getTimer() returns an instance created dynamically, how could the GWT compiler possibly make any assumption about the return value of getTimer(), and the presence/usage of the methods of the Timer type?

When I have seen this kind of errors it was caused by unreachable code: GWT had determined that some code was not reachable, turning off compilation for some stuff, but then it still somehow tried to link the unreachable code, showing this kind of errors.

For completeness sake
If this error shows up (which often happens after deploying to App Engine) then compile without obfuscation, turn off super dev mode, restart jetty and refresh the browser. Open the generated javascript and find where the problem occurs by searching for 'nullMethod'. You'll see that the compiler may have removed whole chunks of code that it believes is 'unreachable'.
The code surrounding 'null.nullMethod' is probably very different than what you expected. The simplest way around this is to add a null /undefined check and initializing whatever variable that is generated as 'null'. This forces the compiler to reconsider because now the variable can never be null and the code that follows it must be reachable.
For example, if null.nullMethod is found and 'null' is actually supposed to be var a = ... then add if(a == null) { a = ""; } before it (in Java of course).

For anybody who struggles with this null.nullMethod issue:
It may be possible that your GWT compiler isn't able to find the properties of your JSON bean object if your object variable is declared with its interface type:
MyTypeIF item = ...;
...
item.getStart();
...
In my scenario, GWT compiled that into:
MyTypeIF item = ...;
...
null.nullMethod();
...
Instead, I had to declare and cast it to its real implementation class:
JSMyType item = (JSMyType)...;
...

Related

How does Js.cast() perform its type checking?

I'm using GWT 2.9 with elemental2-1.0.0-RC1.
The following code throws a ClassCastException at runtime:
DocumentRange documentRange = Js.cast(DomGlobal.document); // Fails
Range range = documentRange.createRange(); // Never reaches here
When I change to use an Js.uncheckedCast() instead, it succeeds:
DocumentRange documentRange = Js.uncheckedCast(DomGlobal.document);
Range range = documentRange.createRange(); // Works
The documentation for Js.uncheckedCast() says:
"You should always prefer regular casting over this (unless you know what you are doing!)."
I don't know why I'm having to use it, so I'm feeling nervous. Can someone explain how Js.cast() performs its type-checking and why I need to use an Js.uncheckedCast() in this instance?
Js.cast() is a way to cheat a bit, and do something that the Java language will not permit, but might actually be legal. Ignoring "how it actually works", the idea is that you can now get past issues where Java would complain, even if it turns out to be legit.
An example could be where you take a java.lang.Double or double and want to treat it as a JsNumber so you can call toPrecision(2) on it. Since java.lang.Double is final, it isn't legal to cast to an unrelated type, but Java doesn't know that in GWT, Double is really just a js Number. So, instead you can perform the cast with Js.cast(). The compiler will insert a runtime type check in there, verifying at runtime that your number is in fact a JS Number instance.
Another example could be trying to extend some native type that elemental2 provides, either to implement a workaround for a missing feature, or to do something browser-specific. Your new class may not extend the existing class - from JS's perspective this is okay, you are just describing the API that you know will exist at runtime. As such, we need to avoid the Java language check of "does this cast even make sense?", and just tell the compiler to try it.
On the other hand, you can "lie" to the compiler with Js.uncheckedCast(). This is used in cases where you are even asking the runtime to skip the check, and just pretend that it will work. This can let you do weird things, like treating Strings as if they were arrays, or solve cross-frame problems. No runtime check will be emitted, so instead you might just get a TypeError if a method/property is missing, instead of a proper ClassCastException.
In elemental2-dom 1.0.0-RC1, there is a class called DocumentRange, but it doesnt really make any sense - it is declared as a class, which means it can be type checked in JS, but the browser spec says that it should be an "interface" (which in JS-land means that it just is a description of a type, rather than something you can typecheck). https://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level2-DocumentRange-method-createRange
This bug is inherited from closure-compiler, which claims that this has a constructor: https://github.com/google/closure-compiler/blob/6a418aa/externs/browser/w3c_range.js#L241-L251
The fix is for closure-compiler to refer to this as an interface, and for a new release of elemental2 to be made so you can use this.
There are two workarounds you can make here. The first is to cheat with Js.uncheckedCast(DomGlobal.document) and say "yes, I know that the Document is not instanceof DocumentRange, but that's because there is no such class as DocumentRange, so just pretend it worked so I can call createRange() on it". This is what you are doing already - it hides the fact there is a bug, but at the end of the day it works.
The "correct" answer is to declare your own DocumentRange, and do a Js.cast() to that instead. This is still gross - you have to keep your new interface around until closure gets fixed, and then elemental2 gets released, and then you have to remember to clean it up.
In this case, I would suggest lying to GWT and using Js.uncheckedCast() - there is only a single method on here, and it is unlikely to change in a meaningful way.

cannot debug GWT native code within gwtmockito

I have a GwtMockitoTestCase and the debugger seems not to enter inside any vanilla GWT class like Widget, ResizeLayoutPanel, etc.
However, when running the same code inside DevMode, the debugger steps correctly through that code.
Does this have to do with GWT running inside a JRE? If not, could it be that my classpath is wrong somehow? Or maybe the gwt-user jar doesn't have debugging information?
I've also tried to extend a GWT class:
ResizeLayoutPanel w = new ResizeLayoutPanel() {
#Override
public void setWidget(Widget pW) {
super.setWidget(pW); (1)
}
};
And breakpoint on line (1) is working but pressing F5, it doesn't go inside ResizeLayoutPanel's setWidget method.
Thank you!
After digging in the GwtMockito code, it seems there are a certain set of classes that are stubbed and some methods' body is removed. Therefore it's not possible to debug those methods.
The question that remains is that somehow GWTMockito breaks the code coverage tool(EclEmma) which shows less code covered than it's supposed to. I've posted a separate question on this topic on SO: false code coverage reported using GwtMockito
Some technical background:
GwtMockitoClassLoader stubs some classes from GWT completely, please check GwtMockitoTestRunner#getClassesToStub() which includes Widget and ResizeLayoutPanel classes.
The stubbing process removes the body completely for the methods returning primitive values or void, see GwtMockitoClassLoader#onLoad. If the return is a java bean, it will return a mocked version for it.

Can't launch from an object

I'm using the current version of the TypeSafe Scala/eclipse IDE. I have an object (which I called PositionObj to give it a unique name). PositionObj contains a main method. Yet when I try Run as > Scala application I get a pop-up message saying:
PositionObj needs to be an 'object' (it is currently a 'class').
In fact it's not a class, and there is no class with that name. Any thoughts about why this is happening and how I can get around it?
Here is the relevant code.
object PositionObj { ...
def main(args: Array[String] = Array[String]()): Unit = {
// This is just to see if anything happens.
println(position(3).p1Rqmts.keys.head)
}
...
Thanks.
Based on your answered-to code, try removing the default argument, since this might be creating a different code signature
I should have done this before, but now I notice that there is a compiler error message that says that the compiler couldn't handle the code because it was too big for a method. That's consistent with my experience with the problem. When I comment out a large table of data, everything works fine. So I'm now convinced that the problem was simply that the program was organized in a way that pieces of it were too large to be handled by the compiler.
I got around the problem by chopping my data table into multiple parts and including each one in a separate object. That worked even though all the objects were then included in the overall program. It was not the size of the program overall; it was the size of large chunks.
The compiler error message was somewhat misleading in that it said the problem was that a method was too large. In fact, my data table was a val in an object and not within a method. But as I said, chopping it up into separate objects and combing them with software solved the problem.

Why am I getting NullPointerException in the CompilationUnit instances returned from ASTParser.createASTs()

I am working on an Eclipse JDT plugin that requires parsing large numbers of source files,
so I am hoping to use the batch method ASTParser.createASTs(). The parsing executes without errors, but within the CompilationUnit instances it produces, many of the org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding instances have had their scope field set to null. This setting to null is occurring in the CompilationUnitDeclaration.cleanUp() methods, which are invoked on a worker thread that is unrelated to my plugin's code (i.e., my plugin's classes do not appear on the cleanUp() method call stack).
My parsing code looks like this (all rawSources are within the same project):
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setIgnoreMethodBodies(false);
parser.setProject(project);
parser.createASTs(rawSources.values().toArray(new ICompilationUnit[0]), new String[0], this, deltaAnalyzer.progressMonitor);
Alternatively, I can execute the parsing this way, and no such problems occur:
for (ICompilationUnit source : rawSources.values())
{
parser.setResolveBindings(true);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setIgnoreMethodBodies(false);
parser.setProject(project);
parser.setSource(source);
CompilationUnit ast = (CompilationUnit)parser.createAST(deltaAnalyzer.progressMonitor);
parsedSources.add(deltaAnalyzer.createParsedSource(source, ast));
}
This issue occurs in both Helios and Indigo (the very latest release build). I filed a bug in Eclipse Bugzilla, but if anyone knows of a way to work around this--or if I am using the API wrong--I would greatly appreciate your help.
Byron
Without knowing exactly what your exception is, I can still offer 2 suggestions:
Have a look at org.eclipse.jdt.ui.SharedASTProvider. If you are not making any changes to ASTs, this class may provide a more robust way of getting the ASTs.
Play around with some of the settings that you are using. Do you really need bindingsRecovery set to true? What about statementRecovery? Setting these to false may help you.

GWT works great in Hosted Mode, and Compiles without error -- but its JS files are buggy

I have no errors show up in either the compilation or the hosted mode process, but the JS that GWT creates contain errors that disallow the proper rendering of the website. How can this happen? Is this a problem with the compiler?
FireBug is giving me nothing, no errors at all.
But I don't know where to go from here or what more information to give you all, since I can't effectively debug JS like this. More fundamentally, I just don't understand why GWT is giving me JS that doesn't work.
EDIT: I didn't really know what Pretty and Detailed meant until now. Thanks for pointing me to this. What I get now is http://i.imgur.com/qUyNb.png.
I'm not sure where to go from here.
EDIT 2: Here is the final image I will post (I promise!): http://i.imgur.com/ZVQVW.png. This is the pretty output. The error reads: "Uncaught com.google.gwt.core.client.JavaScriptException (TypeError): Cannot call method 'isString' of null (anonymous function)."
The resolution to this issue was the realization that isString was not a JNSI method, but instead a method I wrote in a try / catch block. This was the code that tripped me up:
try{something that will create a NullPointerException}
catch(NullPointerException npe){npe.printStackTrace()}
#Luismahou's link above said the following about error-catching in GWT:
Exceptions: try, catch, finally and user-defined exceptions are supported as normal, although Throwable.getStackTrace() is not meaningfully supported in production mode.
Note: Several fundamental exceptions implicitly produced by the Java VM, most notably NullPointerException, StackOverflowError, and OutOfMemoryError, do not occur in production mode as such. Instead, a JavaScriptException is produced for any implicitly generated exceptions. This is because the nature of the underlying JavaScript exception cannot be reliably mapped onto the appropriate Java exception type.
I think what happened is that my try block threw a NullPointerException, which was represented as a JavaScriptException and was uncaught by the catch block. Lesson learned: don't catch NullPointerExceptions, StackOverflowErrors, and OutOfMemoryErrors in GWT.