I have declared a generator in my GWT module descriptor and it seems it is not called when the class which trigger the generator is instanciated via the Ginjector.
public interface MyGinjector extends Ginjector {
MyWidget getMyWidget();
}
public class MyEntryPoint implements EntryPoint {
public static final MyGinjector INJECTOR = GWT.create(MyGinjector.class);
public void onModuleLoad() {
MyWidget myWidget = INJECTOR.getMyWidget(); // [1]
MyWidget myWidget = GWT.create(MyWidget.class); // [2]
RootPanel.add(myWidget);
}
}
[1] The generator is not called.
[2] The generator is called.
Does it mean that the GIN injector does not instanciate object through the GWT.create() method?
Thanks for your help.
Kind regards,
AFAIK, GIN (at least up until 1.5) will only generate a GWT.create() if the class has a public zero-arg constructor that is not annotated with #Inject (otherwise it'll do a new on it)
Related
Firstly, is doing such thing a good practice ?
I tried what seems to be the right way for me but wasn't successful :
public class FormViewImpl extends CompositeView implements HasUiHandlers<C>, FormView {
public interface SettlementInstructionsSearchFormViewUiBinder extends UiBinder<Widget, SettlementInstructionsSearchFormViewImpl> {}
#Inject
static FormViewImpl uiBinder;
#Inject
static Provider<DateEditorWidget> dateEditorProvider;
#UiField(provided = true)
MyComponent<String> myComp;
#UiField
DateEditorWidget effectiveDateFrom;
// .. other fields
#Inject
public FormViewImpl () {
myComp = new MyComponent<String>("lol");
if (uiBinder == null)
uiBinder = GWT.create(SettlementInstructionsSearchFormViewUiBinder.class);
initWidget(uiBinder.createAndBindUi(this));
}
#UiFactory
DateEditorWidget createDateEditor() {
return dateEditorProvider.get();
}
}
What other things than a class with no arguments is required ? In my company's project the same kind of code works at some other place. Sorry from the high level of noob here...
If you guys had any pointers it would be nice.
Thanks
Two issues:
First, two of your #Inject fields are static - have you done anything to make static fields be injected? Static fields don't get set when Gin (or Guice) creates new instances, those have to be set once and done. As they are static, they will never be garbage collected - this may be okay with you, or it might be a problem, and you should change them to instance fields. If you want to keep them static, then you must invoke requestStaticInjection in your module to ask Gin to initialize them when the ginjector is created.
Next, if you do choose to remove static, the uiBinder field must still be null in that constructor, because the fields can't have been injected yet! How do you set a field on an object that you haven't yet created? That's what you are expecting Gin to be able to do. Instead, consider passing that as an argument into the #Inject decorated constructor. You don't even need to save it as a field, since the widget will only use it the one time.
To have a class generated by GIN (doesn't matter if it is a uiBinder or not) it is not necessary for it to have a default constructor (i.e. the one without parameters). The class you want to inject must have the constructor annotated with #Inject:
#Inject
public InjectMeClass(Object a, Object b)
The other class which is injected, suppose it is a UiBinder, must have the injected fields annotated with #UiField(provided=true):
public class Injected extends Composite {
private static InjectedUiBinder uiBinder = GWT
.create(InjectedUiBinder.class);
interface InjectedUiBinder extends UiBinder<Widget, Injected> {
}
#UiField(provided=true)
InjectMeClass imc;
public Injected(final InjectMeClass imc) {
this.imc=imc;
initWidget(uiBinder.createAndBindUi(this));
}
So, back to your case:
#UiField(provided = true)
MyComponent<String> myComp;
#Inject
public FormViewImpl (MyComponent<String> myComp) {
this.myComp = myComp;
and for example:
public class MyComponent<T> extends Composite {
private T value;
#Inject
public MyComponent(T t) {
this.value = t;
...
}
...
}
In the GIN module you can have a provider:
#Provides
#Singleton
public MyComponent<String> createMyComponent() {
return new MyComponent<String>("lol");
}
I'm using gwt-platform and tried to implement GWT's editor framework. But I don't get it working from within the presenter. There are some answers around the web, that say I have to inject the EditorDriver somehow into the Presenter, but I don't know how to do this...
At the moment I tried this without success:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends View, HasUiHandlers<MyUiHandlers>, Editor<MyModel> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
interface Driver extends SimpleBeanEditorDriver<MyModel, MyView> {}
private Driver editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = GWT.create(Driver.class);
editorDriver.initialize(this.getView());
editorDriver.edit(m);
}
...
}
It works if I explicitly specify the ViewImplementation, but that's not the way MVP should work:
interface Driver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> {}
...
editorDriver.initialize((MyViewImpl) this.getView());
I would be nice if someone could give me an example how to do it right.
Thanks
An approach similar to what was used in an earlier version of the Expenses sample worked for me:
An interface that the view should implement. The wildcard is used so that the presenter does not need to know the concrete view implementation:
import com.google.gwt.editor.client.Editor;
import com.gwtplatform.mvp.client.View;
/**
* Implemented by views that edit beans.
*
* #param <B> the type of the bean
*/
public interface BeanEditView<B> extends View, Editor<B> {
/**
* #return a new {#link SimpleBeanEditorDriver} initialized to run
* this editor
*/
SimpleBeanEditorDriver<B, ?> createEditorDriver();
}
Your presenter should look something like this now:
public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
public interface MyView extends BeanEditView<MyModel>, HasUiHandlers<MyUiHandlers> {}
#ProxyStandard
#NameToken(NameTokens.myPage)
#NoGatekeeper
public interface MyProxy extends ProxyPlace<MyPresenter> {}
private SimpleBeanEditorDriver<MyModel, ?> editorDriver;
DispatchAsync dispatcher;
#Inject
public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
super(eventBus, view, proxy);
getView().setUiHandlers(this);
this.dispatcher = dispatcher;
MyModel m = new MyModel();
m.setId(1L);
m.setUsername("username");
m.setPassword("password");
editorDriver = getView().createEditorDriver();
}
...
}
And the view implmementation:
public class MyViewImpl extends ViewWithUiHandlers<MyUiHandlers> implements
MyPresenter.MyView {
public interface Binder extends UiBinder<Widget, MyViewImpl> { }
private static Binder uiBinder = GWT.create(Binder.class);
/**
* The driver to link the proxy bean with the view.
*/
public interface EditorDriver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> { }
private final Widget widget;
public MyViewImpl() {
widget = uiBinder.createAndBindUi(this);
}
#Override
public SimpleBeanEditorDriver<MyModel, ?> createEditorDriver() {
EditorDriver driver = GWT.create(EditorDriver.class);
driver.initialize(this);
return driver;
}
#Override
public Widget asWidget() {
return widget;
}
...
}
That's as close as I could get to MVP with GWT's Editor Framework. I couldn't find a way for the view implementation to NOT know the model but I don't think it's really necessary.
If anyone has any improvements on this, I'm glad to hear.
Found some additional comments on GWT Editors. It seems that it might just not be possible to completely separate the model. As Thomas Broyer puts it in his answer to another Editor question:
"MVP is not set in stone (it's not even defined; it was coined by Martin Fowler but he retired the term in favor of two more specific patterns), so you're only violating the rules you gave to yourself. Put differently, the Editor framework as a whole can be seen as violating MVP: each editor know the model, not necessarily the exact instance it's editing (as with ValueAwareEditor or LeafValue), but at least the kind of objects it's an editor of."
The issue is that the Driver.class passed to GWT.create
editorDriver = GWT.create(Driver.class);
must the concrete class that holds all sub-editors, i.e. all the uibinded widgets.
One solution is the following:
The view interface extends the editor interface for the Model object
public interface MyView extends View, ..., Editor<MyModel>
The view implementation MyViewImpl defines a driver type
interface MyDriverImpl extends SimpleBeanEditorDriver<MyModel,MyViewImpl>
The driver is instantiated in MyViewImpl by
SimpleBeanEditorDriver<MyModel,MyView> driver = GWT.create(MyDriverImpl.class);
The parent type
SimpleBeanEditorDriver<MyModel,MyView>
can be used to pass references of the driver to the presenter
MVP says that you use the presenter to completely seperate the model from the view. In addition I'd say that your approach puts logic inside the view...
I hope that there's another solution ;)
I am having trouble serializing an object over GWT that contains a sub class that is cast to its base class. My class hierarchy is as follows:
public class BaseManagedObject implements IsSerializable
{
public Shortcut getShortcut()
{
return new Shortcut();
}
}
public class User extends BaseManagedObject implements IsSerializable
{
public Shortcut getShortcut()
{
return new DomainMemberShortcut();
}
}
public class Shortcut implements IsSerializeable {}
public class DomainMemberShortcut extends Shortcut implements IsSerializable {}
When I serialize a User object, I get "The response could not be deserialized". If I change User to return a Shortcut in getShortcut(), there is no problem. I added code that references the DomainMemberShortcut, just to verify that I can build with it, and that works fine.
Any suggestions?
Thanks,
Found the solution - I was missing the default no-arg constructor in the DomainMember subclass.
i'm wondering if there's a way to build the gwt uibinder logic into an abstract parent class so that i don't have to repeat the code in every class i want to bind.
for example, i'd like to be able to do something like this:
public abstract class BasePanel<Panel extends BasePanel> extends Composite {
interface Binder<BinderPanel extends BasePanel> extends UiBinder<Widget, BinderPanel> { }
private static final Binder binder = GWT.create(Binder<Panel>.class);
public BasePanel() {
initWidget(binder.createAndBindUi(this));
init();
}
}
basically this would allow any child classes to do something like this:
public MyPanel extends BasePanel<MyPanel> {
//my code here
}
the default constructor would take care of all the code to bind MyPanel to MyPanel.ui.xml.
basically i want to be lazy and only have to build the interface and the binder once so that it's done in a common way. thoughts?
thanks in advance.
Proper way to do abstract UI binder classes is to define a super class that will contain logic that is common to all subclass widgets. This class can have fields marked as #UiField, event handlers and anything else that goes into the UI binder class. And child classes actually have UI binder instantiation logic. So something like this:
public abstract BaseWidget extends Composite {
#UiField TextBox textBoxCommon1;
#UiField TextBox textBoxCommon2;
#UiHandler("textBoxCommon1")
void onTextBoxCommon1Changed( ValueChangeEvent<String> event ) {
//...
}
#UiHandler("textBoxCommon2")
void onTextBoxCommon2Changed( ValueChangeEvent<String> event ) {
//...
}
}
public class SomeWidget extends BaseWidget {
interface SomeWidgetUiBinder extends UiBinder<Widget,SomeWidget> {}
private static SomeWidgetUiBinder uiBinder = GWT.create(SomeWidgetUiBinder.class);
#UiField Button someWidgetButton;
public SomeWidget() {
initWidget(uiBinder.createAndBindUi(this));
}
#UiHandler("someWidgetButton")
void onButtonClicked(ClickEvent e) {
Window.alert(textBoxCommon1.getValue());
}
}
Good morning everybody,
I'm trying to transmit the following calls with an GWT RPC call:
public class MVCController extends Composite implements IsSerializable {
//..
private MVCClass listeners;
public void addListener(MVCClass _listener){
listeners = _listener;
}
//....
}
The MVCClass is the following interface:
import com.google.gwt.user.client.rpc.IsSerializable;
public interface MVCInterface extends IsSerializable{
public abstract void labelTextChange(String _text);
}
Whenever I make the RPC call, the application crashes, saying something about
Failed to create an instance of ... via deferred binding
Can I send an Interface with an RFC call?
Regards Stefan
You can not serialize a gwt widget that is why you get that exception. Your class MVCController extends from Composite whose base class is Widget..