Simple GWT Editor Example - gwt

I'm finding anything other than copying and pasting existing GWT Editor examples to be frustrating. Here's an attempt to create a minimal Editor, without success.
public class ContactEditor extends Composite implements Editor<Contact> {
interface Binder extends UiBinder<Widget, ContactEditor> {}
interface ContactEditorDriver extends
SimpleBeanEditorDriver<Contact, ContactEditor> {}
private final ContactEditorDriver editorDriver;
#UiField TextBox salutation;
public ContactEditor(Contact contact) {
editorDriver = GWT.create(ContactEditorDriver.class);
editorDriver.initialize(this);
editorDriver.edit(contact);
initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
}
}
When this is instantiated with
ContactEditor contactEditor = new ContactEditor(new Contact());
I get an UmbrellaException that contains
Caused by: java.lang.NullPointerException: null
at ...ContactEditor_SimpleBeanEditorDelegate.attachSubEditors(ContactEditor_SimpleBeanEditorDelegate.java:12)
at com.google.gwt.editor.client.impl.AbstractEditorDelegate.initialize(AbstractEditorDelegate.java:264)
at com.google.gwt.editor.client.impl.SimpleBeanEditorDelegate.initialize(SimpleBeanEditorDelegate.java:32)
at com.google.gwt.editor.client.impl.AbstractSimpleBeanEditorDriver.edit(AbstractSimpleBeanEditorDriver.java:45)
at ...ContactEditor.<init>(ContactEditor.java
What's going on here---SubEditors? The failure seems to be in generated code and is hard for me to debug.
Much thanks.

By the time you initialize the editor driver, the "salutation" subeditor isn't initialized yet (still null).
Move your createAndBindUi call before the editor init call.

Related

Injecting all mappers in a list and calling a convert method polymorphically

Is there a way to autowire all mappers written with Mapstruct in Spring just like we used to do with the Spring Converter interface and calling one toEntity(or convert or any other name)? In spring, it is easy because they all implement the same functional interface and by making it inherit from another interface we can determine the right converter in the runtime like below:
import org.springframework.core.convert.converter.Converter;
public interface CustomConverter<S extends ..., T extends ...> extends Covnerter<S,T>{
boolean supports(Class clazz);
}
And then injecting it would be easy:
#Autowire
private final List<CustomConverter> myConverters;
and by calling supports we would determine the right kind of converter and then call convert against it.
I had something like this in mind:
#Mapper
public interface MyMapper extends CustomMapper<MyEntity, MyDto>{
MyMapper INSTANCE = Mappers.getMapper(MyMapper.class);
MyEntity toEntity(MyDto dto);
default boolean supports(Class clazz) {
return MyDto.class.isAssignableFrom(clazz);
}
And
public interface CustomMapper<T extends ..., S extends ...> {
boolean supports(Class clazz);
T toEntity(S dto);
}
This does not work though.
Do you have any suggestions here? I might have misunderstood this all together...Thanks.
Checkout: https://github.com/mapstruct/mapstruct-spring-extensions
The author made and adapter based on a discusion in this SO issue.
A non spring based solution can be found here. Although you need to write your own annotation processor.

Load a ListBox content dynamically on page load

I'm currently working on a simple GWT project. One of the things I'd like to do is that when the page loads I can dynamically populate the contents of a ListBox based on certain criteria. I actually don't see any handlers for a ListBox to handle the initial render event but I see change handlers.
How does one populate a ListBox contents with data from the server side on pageload with GWT?
Right now I have a class that implements EntryPoint that has a
final ListBox fooList = new ListBox();
I also have a set of beans but I also have a class implementing RemoteService. Since I can't seem to get direct calls to my user defined packages directly in the EntryPoint (which makes sense) how do I populate that ListBox with server side content on initial page load? Right now I'm using a List but I figure if I cant get that to work I can get a DB call to work...
I've tried things in the EntryPoint like:
for (String name : FOOS) {
fooList.addItem(name, name);
}
However FOOS would derive from a server side data and the EntryPoint is supposed to be largerly limited to what can compile to JS! I can't get user defined classes to be recognized on that side as that string is the result of a set of user defined classes.
I also tried creating a method in the class implementing RemoteService that returns a ListBox. This also didn't compile when I tried to call this method. Perhaps I don't fully understand how to call methods in a RemoteService service implementing class.
I've searched a lot and I can't find anything that clearly explains the fundamentals on this. My background is much more ASP.NET and JSPs so perhaps I'm missing something.
I'm using GWT 2.6 is that is relevant.
The usual procedure is the following:
Create a bean class for the data you want to transmit between client and server. Let's call it MyBean.
Place MyBean in the shared package of your project.
This class has to implement either Serializable or IsSerializable, otherwise GWT will complain that it doesn't know how to transmit it.
Create your RemoteService that contains the method you want to use to transmit MyBean from/to the server.
Once you get your data on the client using an AsyncCallback and your RemoteService, fill the ListBox using your beans, e.g. by calling MyBean#getName() or MyBean#toString().
Success!
I based my example on the GWT sample project ( I named it example), just replace the classes and it should work :
public class Example implements EntryPoint {
/**
* Create a remote service proxy to talk to the server-side Greeting
* service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final ListBox listBox = new ListBox();
RootPanel.get("sendButtonContainer").add(listBox);
greetingService.getSomeEntries(new AsyncCallback<String[]>() {
#Override
public void onSuccess(String[] result) {
for (int i = 0; i < result.length; i++) {
listBox.addItem(result[i]);
}
}
#Override
public void onFailure(Throwable caught) {
}
});
}
}
This is our EntryPoint, it creates a listbox and calls the server with a AsyncCallback to get some dynamic data. If the call is successfull (onSuccess), the data is written into the listbox.
The GreetingService interface define the synchronous methods, it is implemented in the GreetingServiceImpl class :
#RemoteServiceRelativePath("greet")
public interface GreetingService extends RemoteService {
String[] getSomeEntries() ;
}
The asynchronous counterpart is the GreetingServiceAsync interface, we used it before to call the server :
public interface GreetingServiceAsync {
void getSomeEntries(AsyncCallback<String[]> callback) ;
}
The GreetingServiceImpl class is located on the server. Here you could call for example a database:
#SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
#Override
public String[] getSomeEntries() {
String[] entries = { "Entry 1","Entry 2","Entry 3" };
return entries;
}
}
Now if you want to use some Bean/Pojo between the server and client, replace the String[] in each class/interface with the object name, put the class in the shared package and consider that it implements Serializable/IsSerializable.

GWT null has no properties

I have an issue when I compile the user interface, when i add a method messages.usuario(), Firebug show the error : TypeError: null has no properties
lblUsuario = new Label_2(null.nullMethod()); this is the code of my class :
public class AdministradorMVP implements EntryPoint {
private MessageConstants messages;
#Inject
public void setMensajes(MessageConstants mensajes) {
this.messages = mensajes;
}
private final MyWidgetGinjector injector = GWT.create(MyWidgetGinjector.class);
private Place defaultPlace = new SignInPlace("Admin");
private SimplePanel appWidget = new SimplePanel();
/**
* This is the entry point method.
*/
Label lblUsuario = new Label(messages.usuario());
Label lblNombre = new Label(messages.nombre());
so I can't find the source of the problem, thank you
The GWT compiler generates null.nullMethod() whenever it can statically determine that a particular method is always called on a null reference. In this case, messages has been determined to always be null (either setMensajes is called with a null value or it's not called at all), so messages.usuario() would always throw a NullPointerException, and this is translated into a null.nullMethod() in the generated JavaScript code.
From your code I'm missing the 'boostrap the injection' (see JavaDoc of Ginjector). In other words, you need to trigger the initial inject to take place. Creating MyWidgetGinjector is not enough.
One solution is to add a method void inject(AdministradorMVP entryPoint); to the interface MyWidgetGinjector and in the class AdministradorMVP in onModuleLoad call as (one of) the first statements: injector.inject(this);.

Custom TabLayoutPanel in GWT

I'm trying to create my custom TabLayoutPanel extension, my code is following:
public class ExpandableTabLayoutPanel extends TabLayoutPanel {
#UiConstructor
public ExpandableTabLayoutPanel(double barHeight, Unit barUnit) {
super(barHeight, barUnit);
addExpandableBehaviour();
}
private addExpandableBehaviour(){
//...
}
}
And here I invoke it from UIBinder:
<a:ExpandableTabLayoutPanel barHeight="20" barUnit="PX">
<a:tab>
<a:header>header</a:header>
<a:AdvancedRichTextArea styleName="{style.area}" ui:field="area"/>
</a:tab>
</a:ExpandableTabLayoutPanel>
(I was forced by error messages to use a:tab/a:header instead of g:tab/g:header even if I don't have tab and header defined in my a: package/workspace, but that's probably not the issue)
If #UiConstructor annotation is present over ExpandableTabLayoutPanel like in the listing, I'm getting strange error:
[ERROR] [gwtreproduce] - <a:ExpandableTabLayoutPanel barHeight='20' barUnit='PX'> missing required attribute(s): arg1 barHeight Element <a:ExpandableTabLayoutPanel barHeight='20' barUnit='PX'> (:13)
When I disable #UiConstructor, I'm getting even stranger error:
[ERROR] [gwtreproduce] - Errors in 'generated://E6338B946DFB2D28988DA492134093C7/reproduce/client/TestView_TestViewUiBinderImpl.java' : [ERROR] [gwtreproduce] - Line 33: Type mismatch: cannot convert from TabLayoutPanel to ExpandableTabLayoutPanel
What am I doing wrong with extending TabLayoutPanel?
And side question: how it is possible that TabLayoutPanel constructor isn't annotated with #UiConstructor and can be used in UiBinder (how UiBinder knows which constructor to invoke)?
for you side question : you have to add (provided=true) to the UiField annotation of your widget. Then in the code, set the instance yourself, before createAndBindUi() call like this :
class Whaoo extends Composite{
/* with 'provided', UiBinder don't call any constructor */
#UiField(provided = true)
final Great foo;
interface WhaooUiBinder extends
UiBinder<Widget, Whaoo> {}
private static WhaooUiBinder uiBinder =
GWT.create(WhaooUiBinder.class);
public Whaoo() {
// initialize "provided" before createAndBindUi call
foo = new Great(String bar, int pouet);
initWidget(uiBinder.createAndBindUi(this));
}
}

google-gin a provider needs a dependency. NullPointerException BindingsProcessor.java:498

In my GWT application i'm trying to setup a DI mechanism wihich would allow me to have all the commonly necessary stuff at hand everywhere. I'm using google-gin which is an adaptation of guice for GWT. I have an injector interface defined as this:
#GinModules(InjectionClientModule.class)
public interface MyInjector extends Ginjector {
public PlaceController getPlaceController();
public Header getHeader();
public Footer getFooter();
public ContentPanel getContent();
public EventBus getEventBus();
public PlaceHistoryHandler getPlaceHistoryHandler();
}
My injection module is this:
public class InjectionClientModule extends AbstractGinModule {
public InjectionClientModule() {
super();
}
protected void configure() {
bind(Header.class).in(Singleton.class);
bind(Footer.class).in(Singleton.class);
bind(ContentPanel.class).in(Singleton.class);
bind(EventBus.class).to(SimpleEventBus.class).in(Singleton.class);
bind(PlaceController.class).toProvider(PlaceControllerProvider.class).asEagerSingleton();
bind(PlaceHistoryHandler.class).toProvider(PlaceHistoryHandlerProvider.class).asEagerSingleton();
}
}
When calling MyInjector injector = GWT.create(MyInjector.class); i'm gettign the following exception:
java.lang.NullPointerException: null
at com.google.gwt.inject.rebind.BindingsProcessor.createImplicitBinding(BindingsProcessor.java:498)
at com.google.gwt.inject.rebind.BindingsProcessor.createImplicitBindingForUnresolved(BindingsProcessor.java:290)
at com.google.gwt.inject.rebind.BindingsProcessor.createImplicitBindingsForUnresolved(BindingsProcessor.java:278)
at com.google.gwt.inject.rebind.BindingsProcessor.process(BindingsProcessor.java:240)
at com.google.gwt.inject.rebind.GinjectorGeneratorImpl.generate(GinjectorGeneratorImpl.java:76)
at com.google.gwt.inject.rebind.GinjectorGenerator.generate(GinjectorGenerator.java:47)
at com.google.gwt.core.ext.GeneratorExtWrapper.generate(GeneratorExtWrapper.java:48)
at com.google.gwt.core.ext.GeneratorExtWrapper.generateIncrementally(GeneratorExtWrapper.java:60)
at com.google.gwt.dev.javac.StandardGeneratorContext.runGeneratorIncrementally(StandardGeneratorContext.java:647)
at com.google.gwt.dev.cfg.RuleGenerateWith.realize(RuleGenerateWith.java:41)
at com.google.gwt.dev.shell.StandardRebindOracle$Rebinder.rebind(StandardRebindOracle.java:78)
at com.google.gwt.dev.shell.StandardRebindOracle.rebind(StandardRebindOracle.java:268)
at com.google.gwt.dev.shell.ShellModuleSpaceHost.rebind(ShellModuleSpaceHost.java:141)
at com.google.gwt.dev.shell.ModuleSpace.rebind(ModuleSpace.java:585)
at com.google.gwt.dev.shell.ModuleSpace.rebindAndCreate(ModuleSpace.java:455)
at com.google.gwt.dev.shell.GWTBridgeImpl.create(GWTBridgeImpl.java:49)
at com.google.gwt.core.client.GWT.create(GWT.java:97)
The problem is that the PlaceController class actually depends on one of the other dependencies. I've implemented it's provider like this:
public class PlaceControllerProvider implements Provider<PlaceController> {
private final PlaceController placeController;
#Inject
public PlaceControllerProvider(EventBus eventBus) {
this.placeController = new PlaceController(eventBus);
}
#Override
public PlaceController get() {
return placeController;
}
}
what should i change for this to work?
Old question but having the same problem I kept falling here. I finally found the way to know which class is messing during ginjection.
When I launch my app in development mode and put stack to Trace, I noticed there is a step called : "Validating newly compiled units".
Under this, I had an error but I didn't notice it since I had to expand 2 nodes which weren't even in red color.
The error was "No source code available for type com.xxx.xxxx ...", which was due to a bad import on client side which couldn't be converted to Javascript.
Hope this may help other here !
While I'm not actually seeing how the errors you're getting are related to the PlaceController being injected, I do see that the provider is returning a singleton PlaceController even if the provider were not bound as an eager singleton or in a different scope. The correct way to write that provider would be:
public class PlaceControllerProvider implements Provider<PlaceController> {
private final EventBus eventBus;
#Inject
public PlaceControllerProvider(EventBus eventBus) {
this.eventBus = eventBus;
}
#Override
public PlaceController get() {
return new PlaceController(eventBus);
}
}
Let guice handle the scoping i.e. "Letting guice work for you".
Other than that, I almost bet that your problem is due to the use of asEagerSingleton. I recommend you try this with just in(Singleton.class) and I further posit that you didn't really need the singleton to be eager. It seems others had problems with the behavior too, there's some indication that it has to do with overusing asEagerSingleton or misunderstanding the #Singleton annotation in a few cases.
I also got a lot of NullPointerException warnings using GIN 1.x with no real explanation of what happened. When I upgraded to gin 2.0 I was told with high accuracy what the error was. You might be helped by upgrading to the 2.0 version that was released a year after you asked this question.
Had the same problem problem, same trace, and the error was that I used "server" classes in my "client" classes, so GIN can't find these classes.
I mean by "server" and "client" the packages in my project.
Hope this could help