-
1. Re: Re-writing an existing GWT app in Errai
csa Jan 16, 2014 7:41 PM (in response to datsunhls30)1 of 1 people found this helpfulHi Mike,
Thanks for the feedback about the missing tutorial/guide. I've added a JIRA for a new tutorial that shows how to add Errai to an existing GWT application:
https://issues.jboss.org/browse/ERRAI-684
I am glad you had success getting up and running!
Regarding DevMode performance:
- Breaking down your app into separate GWT modules will definitely improve the startup and refresh time!
- A simpler way to achieve the same (in case modularization is a lot of work) is to configure white or black lists of types. So, basically you can tell Errai IOC which types or packages to ignore when generating code: ErraiApp.properties - Errai - Project Documentation Editor
- DevMode performance is a main area of focus for us in Errai 3 (and in GWT 3 as well). We've already made progress on speeding it up for marshalling on a separate branch that will hopefully be ready and merged into master in the next couple of days.
Cheers,
Christian
-
2. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 17, 2014 3:21 PM (in response to csa)So a few steps forward: I was working on 2.4.3 Final as I was hesitant to work off of an in-progress release, but the white/black lists are 3.0. I upgraded to3.0.0.20131205-M3 and started by configuring the whitelist like:
errai.ioc.whitelist=com.mycompany.app.myapp.client.local.* \
com.mycompany.app.myapp.client.shared.* \
com.mycompany.app.myapp.server.*
I kept getting NullPointerExceptions(pasted below for reference). Running the debugger a bit, I learned that I needed to be whitelisting com.google.gwt.* It might be helpful on TypeInjector.getBeanInstance on or about line 219 to do something like:
if(creationalCallbackVarName == null)
throw new InjectionFailure("Failed to instantiate field: " + injectableInstance.getField().getName() + " type: " + injectableInstance.getField().getGenericType())
Also, it might not fit, but adding com.google.gwt.* to the implicitWhiteList in InjectionContext seems like a reasonable sanity measure too.
Unfortunately, this didn't really bring the refresh time down in development mode, it hovers right at 20 seconds per refresh :-/
NPE for not whitelisting com.google.gwt.*
-----------------------------------------------------------------------
java.util.concurrent.ExecutionException: java.lang.NullPointerException
at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
at java.util.concurrent.FutureTask.get(FutureTask.java:83)
at org.jboss.errai.config.rebind.AsyncGenerators$FutureWrapper.get(AsyncGenerators.java:112)
at org.jboss.errai.config.rebind.AsyncGenerators$FutureWrapper.get(AsyncGenerators.java:86)
at org.jboss.errai.config.rebind.AbstractAsyncGenerator.startAsyncGeneratorsAndWaitFor(AbstractAsyncGenerator.java:100)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCGenerator.generate(IOCGenerator.java:58)
at com.google.gwt.core.ext.IncrementalGenerator.generateNonIncrementally(IncrementalGenerator.java:40)
at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:657)
at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:41)
at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:79)
at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:276)
at com.google.gwt.dev.shell.ShellModuleSpaceHost.rebind(ShellModuleSpaceHost.java:141)
at com.google.gwt.dev.shell.ModuleSpace.rebind(ModuleSpace.java:595)
at com.google.gwt.dev.shell.ModuleSpace.rebindAndCreate(ModuleSpace.java:465)
at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:49)
at com.google.gwt.core.shared.GWT.create(GWT.java:57)
at com.google.gwt.core.client.GWT.create(GWT.java:85)
at org.jboss.errai.ioc.client.Container.bootstrapContainer(Container.java:62)
at org.jboss.errai.ioc.client.Container.onModuleLoad(Container.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.google.gwt.dev.shell.ModuleSpace.onLoad(ModuleSpace.java:406)
at com.google.gwt.dev.shell.OophmSessionHandler.loadModule(OophmSessionHandler.java:200)
at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:526)
at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NullPointerException
at org.jboss.errai.codegen.builder.impl.StatementBuilder.loadVariable(StatementBuilder.java:198)
at org.jboss.errai.codegen.util.Stmt.loadVariable(Stmt.java:202)
at org.jboss.errai.ioc.rebind.ioc.injector.basic.TypeInjector.getBeanInstance(TypeInjector.java:220)
at org.jboss.errai.ioc.rebind.ioc.injector.InjectUtil.getInjectorOrProxy(InjectUtil.java:526)
at org.jboss.errai.ioc.rebind.ioc.injector.InjectUtil.getInjectorOrProxy(InjectUtil.java:440)
at org.jboss.errai.ioc.rebind.ioc.injector.api.InjectionTask.doTask(InjectionTask.java:116)
at org.jboss.errai.ioc.rebind.ioc.injector.InjectUtil.handleInjectionTasks(InjectUtil.java:163)
at org.jboss.errai.ioc.rebind.ioc.injector.InjectUtil.access$000(InjectUtil.java:72)
at org.jboss.errai.ioc.rebind.ioc.injector.InjectUtil$2.generateConstructor(InjectUtil.java:150)
at org.jboss.errai.ioc.rebind.ioc.injector.basic.TypeInjector.renderProvider(TypeInjector.java:138)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCConfigProcessor$3.handle(IOCConfigProcessor.java:414)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCConfigProcessor$7.process(IOCConfigProcessor.java:679)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCConfigProcessor.process(IOCConfigProcessor.java:625)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCBootstrapGenerator.generateBootstrappingClassSource(IOCBootstrapGenerator.java:292)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCBootstrapGenerator.generate(IOCBootstrapGenerator.java:142)
at org.jboss.errai.ioc.rebind.ioc.bootstrapper.IOCGenerator.generate(IOCGenerator.java:68)
at org.jboss.errai.config.rebind.AbstractAsyncGenerator$1.call(AbstractAsyncGenerator.java:43)
at org.jboss.errai.config.rebind.AbstractAsyncGenerator$1.call(AbstractAsyncGenerator.java:40)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
-
3. Re: Re-writing an existing GWT app in Errai
csa Jan 17, 2014 4:01 PM (in response to datsunhls30)Thanks, I've added com.google.gwt.* to the implicit type whitelist. I am definitely eager to find out why refreshing takes 20s in your case. Any diagnostic information you can provide would really be helpful.
For instance your console should log statements like this after refreshing: "generated marshalling class in ..ms", "generated IOC boostrapping class in ..ms". You can find those generated classes in your .errai folder (they should also point us to where the time is spent).
Cheers,
Christian
-
4. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 17, 2014 5:32 PM (in response to csa)I don't see exactly the log statements you're looking for in the devmode gui logs (which I set to -logLevel DEBUG). If I need to increase logging elsewhere, let me know. Also, the increased logging significantly slows it down too, adding about 10s it seems. In case you're wondering, I have a pretty quick development workstation with SSDs -- non-errai devmode is plenty fast.
00:00:38.897 [INFO] Loading module erraitest
... ( stuff that takes about 3.3s)
00:00:42.279 [DEBUG] Rebinding org.jboss.errai.marshalling.client.api.MarshallerFactory
00:00:46.600 [INFO] Checking ErraiApp.properties for configured types ...
00:00:53.700 [DEBUG] Generator returned type 'org.jboss.errai.marshalling.client.api.MarshallerFactoryImpl; mode USE_ALL_NEW_WITH_NO_CACHING; in 10885 ms
00:00:56.068 [DEBUG] Rebinding org.jboss.errai.marshalling.client.api.MarshallerFramework
00:00:56.101 [DEBUG] Rebinding org.jboss.errai.bus.client.api.messaging.MessageBus
... (rebinding standard GWT packages) ...
00:01:05.850 [DEBUG] Rebinding org.jboss.errai.ioc.client.QualifierEqualityFactory
00:01:06.355 [DEBUG] Rebinding org.jboss.errai.ioc.client.container.IOCEnvironment
00:01:06.366 [DEBUG] Rebinding org.jboss.errai.ioc.client.Bootstrapper
00:01:06.881 [DEBUG] Rebinding org.jboss.errai.databinding.client.BindableProxyLoader
...
00:01:07.155 [INFO] Module erraitest has been loaded
-
5. Re: Re-writing an existing GWT app in Errai
csa Jan 20, 2014 5:15 PM (in response to datsunhls30)Hi Mike,
From the log it looks like generating the marshallers took almost 11 seconds. Do you have a lot of @Portable types in your project?
I have just pushed the marshaller generator improvements which speed up marshaller generation quite a bit. Can you try using the latest 3.0-SNAPSHOTs and see if it improves this situation? For our test suite and a community user (who built a huge application) this change made a big difference.
Cheers,
Christian
-
6. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 21, 2014 2:15 PM (in response to csa)Still taking roughly 20 seconds to refresh on 3.0-SNAPSHOT. I do see that the timing from before that was 11 seconds is down to 6 seconds, looks like a big improvement!
To answer your other question, we currently have 2 classes defined as @Portable, 1 class is @EntryPoint, and 1 class is @Templated as we're still evaluating this as a new platform. For the fun of it, I deleted everything that wasn't Errai from our project, and I can refresh DevMode in about 2 seconds. I've also tried pretty exhaustively to white/black-list out everything except the Errai code. My guess is that something is still scanning the non-Errai code we have.
Unless you know of other things I should try, I'm going to try to re-structure some to lower the class-scanning overhead. We have about 1,500 java/GWT UI files and (unfortunately) that expands out to around 10,000 .class files since we have a ton of anonymously implemented callbacks, handlers, etc.
Thanks,
Mike
-
7. Re: Re-writing an existing GWT app in Errai
csa Jan 21, 2014 3:11 PM (in response to datsunhls30)OK thanks for the update. You can take a look at all the generated Errai files in your .errai folder, especially the generated BootstrapperImpl.java. It should NOT contain the classes you blacklisted. Is that the case for you?
Looking through our scanning logic I see that our GwtValidatorScanner that doesn't limit itself to Errai modules (GWT modules that have an ErraiApp.properties). So, that's a scanner that would run through the whole classpath. Do you inherit from org.jboss.errai.validation.Validation? If so, there's a special blacklist property you could use (errai.validation.blacklist).
We are actively working on improving the DevMode start up and refresh performance. Any feedback you have is really appreciated!
Thanks,
Christian
-
8. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 21, 2014 4:23 PM (in response to csa)BootstrapperImpl.java is ~600 lines long and only contains references to the 4 classes that I would expect.
I was not inheriting org.jboss.errai.validation.Validation, but I added it and the blacklist property, and had no discernible difference. I think the net result of adding it and blacklisting it was to tell it to do nothing though
Could you inspect all matching annotated classes/templates and if the sum-total hash of all the files was unchanged from the previous generate operation, you skip that phase and just let it use the old copies? I don't know much about the intricacies of your libraries and may be over-simplifying what you need to do, but that's what we do in some of the in-house model/view/controller generator code we have to keep from constantly re-generating the same code.
-
9. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 28, 2014 10:00 AM (in response to datsunhls30)So I've spent the last few days on 3.0-SNAPSHOT with some successes and some failures, one thing I'm confused about is the (seemingly) rigorous package structure needed for Errai to function properly. In the sample archetype, there are 3 main packages:
client.local
client.shared
server
It was my understanding that the package structure was somewhat flexible as long as an ErraiApp.properties existed in the classpath, but when I attempt to refactor "client.shared" to "shared" I get no errors, but the frontend javascript silently fails afterward. I can reproduce this with the simple-cdi archetype as well. Is this by design or a bug? If it's by design, is there a way to detect that the class structure isn't correct and throw an Exception rather than silently failing?
Thanks,
Mike
-
10. Re: Re-writing an existing GWT app in Errai
csa Jan 28, 2014 11:08 AM (in response to datsunhls30)1 of 1 people found this helpfulHi,
It's a convention by GWT that everything under .client will be considered client-side code and compiled to JavaScript. If you just refactor from .client to .shared (as opposed to client.shared) you effectively have no more client-side code.
If you want to change this default you can specify a source path in your gwt.xml file (i.e. <source path="shared" />):
http://www.gwtproject.org/doc/latest/DevGuideOrganizingProjects.html#DevGuideModuleXml
Cheers,
Christian
-
11. Re: Re-writing an existing GWT app in Errai
datsunhls30 Jan 28, 2014 11:55 AM (in response to csa)Ha, shoot...you're right. Apologies for throwing blame on that one