Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

java.util.Objects.equals(string, string) not found in GWTTestCase #9522

Closed
VaiTuomoMakela opened this issue May 9, 2017 · 11 comments
Closed

Comments

@VaiTuomoMakela
Copy link

GWT version: 2.8.1
Browser (with version): Any
Operating System: Any

Description

While running GWT test cases from Maven, I got the following error message:

[INFO] -------------------------------------------------------
[INFO]  T E S T S
[INFO] -------------------------------------------------------
[INFO] Running equals.string.client.GwtTestEqualsString
[INFO] Starting Jetty on port 0
[INFO]    [WARN] ServletContainerInitializers: detected. Class hierarchy: empty
[INFO] Starting http://localhost:56434/equals.string.EqualsStringJUnit.JUnit/junit.html?gwt.codesvr=localhost:56432 on browser FF38
[INFO] 200 - GET /equals.string.EqualsStringJUnit.JUnit/junit.html?gwt.codesvr=localhost:56432 (127.0.0.1)
[INFO] 200 - GET /equals.string.EqualsStringJUnit.JUnit/equals.string.EqualsStringJUnit.JUnit.nocache.js (127.0.0.1)
[INFO] 200 - GET /equals.string.EqualsStringJUnit.JUnit/equals.string.EqualsStringJUnit.JUnit.devmode.js (127.0.0.1)
[INFO] 200 - GET /equals.string.EqualsStringJUnit.JUnit/gwt/standard/standard.css (127.0.0.1)
[INFO] Module equals.string.EqualsStringJUnit.JUnit has been loaded
[INFO] 200 - POST /equals.string.EqualsStringJUnit.JUnit/junithost (127.0.0.1) 221 bytes
[INFO] 200 - POST /equals.string.EqualsStringJUnit.JUnit/equalsstring/greet (127.0.0.1) 182 bytes
[INFO] 200 - POST /equals.string.EqualsStringJUnit.JUnit/junithost (127.0.0.1) 193 bytes
[INFO] Tests run: 2, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 6.168 sec <<< FAILURE!
[INFO] testFieldVerifier(equals.string.client.GwtTestEqualsString)  Time elapsed: 0.058 sec  <<< ERROR!
**[INFO] java.lang.NoSuchMethodError: java.util.Objects.equals(Ljava/lang/String;Ljava/lang/String;)Z**
[INFO]  at equals.string.shared.FieldVerifier.isEqual(FieldVerifier.java:46)
[INFO]  at equals.string.client.GwtTestEqualsString.testFieldVerifier(GwtTestEqualsString.java:40)
[INFO]  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[INFO]  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
...

The problematic call is here:
https://github.com/VaiTuomoMakela/GwtEqualsStringTest/blob/master/src/test/java/equals/string/client/GwtTestEqualsString.java#L40
Which calls the code in here:
https://github.com/VaiTuomoMakela/GwtEqualsStringTest/blob/master/src/main/java/equals/string/shared/FieldVerifier.java#L46

The function works fine when done in test application:
https://github.com/VaiTuomoMakela/GwtEqualsStringTest/blob/master/src/main/java/equals/string/client/EqualsString.java#L120

Steps to reproduce

Clone test project from https://github.com/VaiTuomoMakela/GwtEqualsStringTest/

Run tests with:
mvn clean verify

The actual demo web application works fine with the same comparison as can be tested by running:
mvn gwt:run
and giving name "string" in the text field.

Known workarounds

Test works fine with GWT 2.8.0

Reverting commit 1c6a4e5c72102d9930e7d71e1be0b35d929b77c7 fixes the issue as well.

@tbroyer
Copy link
Member

tbroyer commented May 9, 2017

Note that devmode is deprecated, and GWT defaults to running tests in prod mode since 2.8.0-rc1 (but the legacy GWT Maven plugin still forces them to devmode by default).

Test passes when run in prod mode: https://gwt-maven-plugin.github.io/gwt-maven-plugin/test-mojo.html#productionMode

I suspect this is a bug in devmode that compiles FieldVerifier.java against the super-source of java.util.Objects (and thus bytecode references the (string;string) overload) but then runs it against the JDK java.util.Objects.

See also discussion in https://gwt-review.googlesource.com/c/17221: it was detected that this would break in devmode, and decided that because devmode is deprecated it wasn't a problem worth worrying at.

I'm tempted to close this as "wontfix". @gkdn?

@VaiTuomoMakela
Copy link
Author

VaiTuomoMakela commented May 9, 2017

Thanks for the quick response and help with the issue.

I was able to configure my project based on given information and now it is working fine with the new 2.8.1 as well.

This is a good solution for me, so feel free to close the tickets as suggested.

Best Regards, . Tuomo

@gkdn
Copy link
Contributor

gkdn commented May 9, 2017

@tbroyer Yes it was known to break dev-mode if the user ends up using new API and decided ok since dev-mode is deprecated.
Wontfix SGTM.

@vojtechszocs
Copy link

Hi, we've run into the same issue in oVirt Engine project after upgrading from 2.8.0 to 2.8.1 😞

As @tbroyer mentioned in his comment, when using classic dev mode, one gets java.lang.NoSuchMethodError on java.util.Objects#equals(String,String) since the JDK version of java.util.Objects has no such method.

Our GWT application is very complex, classic dev mode (with Firefox 26 or equivalently old Chrome) is the only reliable way to debug the code. That's mainly due to big amounts of JS emitted by GWT compiler (which is mainly caused by tight coupling of frontend and backend through GWT RPC).

Our numbers are roughly like this:

Build type Initial JS download size
production (optimized) ~6 M
draft (unoptimized) ~81 M
SDM-generated ~116 M

Chrome consistently crashes when trying to debug with super dev mode and using SDBG isn't very reliable for us. Our experience shows that super dev mode (source maps) just doesn't scale with JS size, once you reach big numbers.

I understand that classic dev mode is deprecated and you're planning to remove it in the future, but I don't think that having something marked as deprecated warrants a "wontfix" resolution. We'll probably end up with either a workaround or downgrade to 2.8.0 😞 sorry for the rant, just wanted to let you know that this bug has implications on existing, large projects like ours.

@gregsheremeta
Copy link

gregsheremeta commented Jun 2, 2017

Effectively killing off classic devmode in 2.8.0 is [edit: would have been] understandable. Doing that in 2.8.1 goes against a typical .z release, IMO. It would be nice if its death could wait until 2.9 or 3.0, whichever.

@niloc132
Copy link
Contributor

niloc132 commented Jun 2, 2017

The problem here is that legacy dev mode will work fine, as long as you stick to Java 7 features - we havent fully supported it working with Java 8 (and there are almost certainly other issues). No one has been interested in helping to test or maintain it until after final releases have been cut.

Legacy dev mode isn't dead, it just isn't supported for anything new - no jsinterop, no newly added JRE emulation, and we've moved off of it for the defaults for GWTTestCase and the dev mode launcher.

With that said, Objects.equals is Java7 and has been supported since well before GWT 2.8.0, so we might consider an exception here, as we've broken existing code, not a newly added API.

@vojtechszocs
Copy link

The problem here is that legacy dev mode will work fine, as long as you stick to Java 7 features - we havent fully supported it working with Java 8 (and there are almost certainly other issues).

Thanks, that's good to know. I wasn't aware of that.

Some time ago, we've upgraded from GWT 2.6.1 to 2.8.0 and immediately switched to using Java 8 syntax / APIs in our client code. We might consider switching to Java 7 compliance 🌵 (it would be quite painful, but probably safest) but aside this issue, classic dev mode still worked for us with 2.8.0.

Legacy dev mode isn't dead, it just isn't supported for anything new

But it's deprecated and will be eventually removed, right? (AFAIK, there were plans to remove it in 3.0 release.)

With that said, Objects.equals is Java7 and has been supported since well before GWT 2.8.0

+1

We could work around this by having a custom super-source of Objects but.. you know 😃 fixing this in GWT itself would be best for us.

@niloc132
Copy link
Contributor

niloc132 commented Jun 2, 2017

At this time, there is no question that legacy dev mode will be removed in GWT 3, short of someone finding a way for modern browsers to make a blocking connection back to the JVM (and the plugin changes in both Chrome and FF have made this impossible, short of blocking XHR calls, which have been tried and produces an unbearably slow experience).

Something like what TeaVM does, where it allows remote debugging could be possible, but my understanding is that it sacrifices blocking calls in order to achieve this. I'm not aware of anyone actively looking into this for GWT at this time, or who has expressed interest.

You may well find that Java8 works, but it has not been tested. JsInterop definitely will not work, which will cause problems for any tooling/library which has hopes of being GWT 3 compatible.

At least in this case, "fixing" Objects would result in performance degradation, or (as I understand it) incompatibility with J2CL, so isn't terribly likely. We can consider looking into fixing legacy dev mode itself, but that may require more work than volunteers are likely to do.

@gkdn
Copy link
Contributor

gkdn commented Jun 2, 2017

If devmode is very critical for you, why don't you just not use Objects.equals which is newly introduced in GWT emulation anyway?

@gkdn
Copy link
Contributor

gkdn commented Jun 2, 2017

BTW, the change is not for J2CL compatibility; it was for improving performance.

@JamesXNelson
Copy link

JamesXNelson commented Jun 2, 2017

The biggest killer of legacy devmode, AFAIK, is the 16-bit address space used to reference methods in classes (16 bits for classes, 16 for methods), which blows up when you have a lot of JSOs (extends JavaScriptObject, not @JsType... which, as Colin mentioned, have no support path whatsoever for legacy dev mode), as all native methods wind up being globbed onto a generated JavaScriptObject$ class.

Per-class impedance mismatch for emulation is certainly fixable; if users have very large codebases that survive on deprecated-but-not-gone features, it is worth seeking low-cost workarounds. In this case, picking a different .equals() implementation is certainly doable, and, while it might seem extreme, one could go so far as making the legacy dev mode classloader apply a set of arbitrary patches (a la https://github.com/gwt-test-utils/gwt-test-utils ).

TBH, gwt-test-utils makes it possible to patch any method for tests only, and is worth keeping in your toolbelt. I found that checking it out, and adding new patches for a Gwt upgrade was quite smooth.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants