Ah, thanks Jens. I'm learning a lot about the GWT compiler!
It would be nice, in these situations, when using the codeserver, if GWT
somehow either:
- Marked that line as not being able to put a breakpoint on, or
- Inserted a dummy line of JS code that allowed the breakpoint to be added
in the correct place.
Maybe doing either of these just isn't possible. It's just that I've
wasted a bit of time in the past wondering why my breakpoints don't hit. I
usually get around it by adding a line of logging and putting a breakpoint
on that.
On Thursday, 18 December 2025 at 1:35:48 am UTC+11 Jens wrote:
> In such a case you can keep the breakpoint you set in the Java file in the
> browser and then open dev tools settings and disable sourcemaps. Then
> reload the page and you see the original JS code. To better understand it
> you can also add <style>PRETTY</style> to your root pom.xml below the
> <launcherDir> configuration of the gwt-maven-plugin.
>
> You will see something like below with the bold line being the breakpoint
> you set (I have added some comments above the functions):
>
> // thats the class initializer of MyHandler. It is empty because there is
> no static {} block in Java
> function $clinit_App$1MyHandler_0_g$(){
> $clinit_App$1MyHandler_0_g$ = Object;
> $clinit_Object_0_g$();
> }
>
> // Thats the default constructor which receives everything that the nested
> MyHandler class can reach in the outer class App.
> function App$1MyHandler_1_g$(this$0_0_g$, val$errorLabel_0_g$,
> val$nameField_0_g$, val$sendButton_0_g$, val$textToServerLabel_0_g$,
> val$serverResponseLabel_0_g$, val$dialogBox_0_g$, val$closeButton_0_g$){
> $clinit_App$1MyHandler_0_g$();
> this.this$01_1_g$ = this$0_0_g$;
> this.val$errorLabel2_0_g$ = val$errorLabel_0_g$;
> this.val$nameField3_0_g$ = val$nameField_0_g$;
> this.val$sendButton4_0_g$ = val$sendButton_0_g$;
> this.val$textToServerLabel5_0_g$ = val$textToServerLabel_0_g$;
> this.val$serverResponseLabel6_0_g$ = val$serverResponseLabel_0_g$;
> this.val$dialogBox7_0_g$ = val$dialogBox_0_g$;
> this.val$closeButton8_0_g$ = val$closeButton_0_g$;
> Object_1_g$.call(this);
> this.$init_1443_g$();
> }
>
> // defineClass creates an underscore variable which is used to define all
> the functions of MyHandler.
> defineClass_0_g$(5, 1, {5:1, 757:1, 838:1, 891:1, 1:1},
> App$1MyHandler_1_g$);
>
> // thats the instance initializer of MyHandler called by the constructor
> above. It is empty because MyHandler does not have instance variables
> _.$init_1443_g$ = function $init_3_g$(){
> $clinit_App$1MyHandler_0_g$();
> }
> ;
>
> // thats the lambda definition that you have used in the delay function.
> *_.lambda$0_72_g$ = function lambda$0_1_g$(){*
> $clinit_App$1MyHandler_0_g$();
> {
> this.sendNameToServer_1_g$();
> }
> }
> ;
>
> // Here you see how GWT uses the lambda you have defined.
> // GWT still uses for lambdas the same logic as for anonymous classes.
> // So App$1MyHandler$lambda$0$Type_1_g$ is actually a class implementing
> the functional interface
> // and it receives the outer scope (MyHandler) so its execute() method
> (from the interface) can
> // call the lambda defined above on MyHandler.
> _.onClick_5_g$ = function onClick_1_g$(event_0_g$){
> delay_0_g$(1000, new App$1MyHandler$lambda$0$Type_1_g$(this));
> }
> ;
> _.onKeyUp_5_g$ = function onKeyUp_0_g$(event_0_g$){
> if (event_0_g$.getNativeKeyCode_1_g$() == 13) {
> this.sendNameToServer_1_g$();
> }
> }
> ;
> _.sendNameToServer_1_g$ = function sendNameToServer_0_g$(){
> $clinit_App$1MyHandler_0_g$();
> var textToServer_0_g$;
> this.val$errorLabel2_0_g$.setText_15_g$('');
> textToServer_0_g$ = this.val$nameField3_0_g$.getText_14_g$();
> if (!isValidName_0_g$(textToServer_0_g$)) {
> this.val$errorLabel2_0_g$.setText_15_g$('Please enter at least four
> characters');
> return;
> }
> this.val$sendButton4_0_g$.setEnabled_4_g$(false);
> this.val$textToServerLabel5_0_g$.setText_15_g$(textToServer_0_g$);
> this.val$serverResponseLabel6_0_g$.setText_15_g$('');
>
> this.this$01_1_g$.greetingService_0_g$.greetServer_1_g$(textToServer_0_g$,
> new App$1MyHandler$1_1_g$(this, this.val$dialogBox7_0_g$,
> this.val$serverResponseLabel6_0_g$, this.val$closeButton8_0_g$));
> }
> ;
>
> // this creates the class literal for MyHandler
> var La_App$1MyHandler_2_classLit_0_g$ = createForClass_0_g$('a',
> 'App/1MyHandler', 5, Ljava_lang_Object_2_classLit_0_g$);
>
>
> So when you place the breakpoint at the line you have used JS sourcemaps
> maps that line to the definition of the lambda and not the call to delay().
> I am not sure if there is a right or wrong because it has to choose between
> the two and generally before you can call delay() the lambda must be
> created. So I think it is logical that way. In such cases you better place
> the breakpoint inside the delay() function.
>
> -- J.
>
> Craig Mitchell schrieb am Mittwoch, 17. Dezember 2025 um 09:07:01 UTC+1:
>
>> I also just noticed, the breakpoint doesn't get hit when you click the
>> "send" button on the page (when it should get hit).
>>
>> On Wednesday, 17 December 2025 at 7:03:18 pm UTC+11 Craig Mitchell wrote:
>>
>>> When debugging in Chrome, sometimes my breakpoints get hit on a page
>>> refresh, but the code is not executed (nor should it be).
>>>
>>> I reproduced the issue with the following:
>>>
>>> 1. Create a sample project with
>>> https://github.com/NaluKit/gwt-maven-springboot-archetype:
>>> mvn archetype:generate -DarchetypeGroupId=com.github.nalukit.archetype
>>> -DarchetypeVersion=LATEST -DarchetypeArtifactId=modular-springboot-webapp
>>>
>>> (use any values, I just entered "a" for everything)
>>>
>>> 2. Modify the a-client\src\main\java\a\App.java with the following:
>>>
>>> 2.1 Add this static method:
>>> public static void delay(int delayMs, com.google.gwt.user.client.Command
>>> run) {
>>> com.google.gwt.core.client.Scheduler.get().scheduleFixedDelay(() -> {
>>> run.execute();
>>> return false;
>>> }, delayMs);
>>> }
>>>
>>> 2.2 In the MyHandler class onClick, call the static method:
>>> public void onClick(ClickEvent event) {
>>> delay(1000, () -> {
>>> sendNameToServer();
>>> });
>>> }
>>>
>>> 3. Start it up:
>>> 3.1: mvn gwt:codeserver -pl *-client -am
>>> 3.2: mvn spring-boot:run -pl *-server -am
>>>
>>> 4. Open it in Chrome: http://localhost:8080/
>>>
>>> 5. Open the Chrome debugger, put a breakpoint on the line:
>>> delay(1000, () -> {
>>>
>>> 6. Refresh the page. The breakpoint gets hit. It looks like this:
>>> [image: Screenshot 2025-12-17 185721.png]
>>>
>>> It doesn't have a call stack, and if you try to step into it, it doesn't
>>> step into the delay method.
>>>
>>> Any idea why this occurs?
>>>
>>
--
You received this message because you are subscribed to the Google Groups "GWT
Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/google-web-toolkit/6cd54e22-6158-4e2b-b993-47430a625d27n%40googlegroups.com.