0
votes

I have a simple bean:

public class SimpleBean implements Serializable {
    String stringMe;
    double autoboxMe;
    // ... boilerplate ...
}

I have created a view implementing Editor.

public class View extends Component implements Editor<SimpleBean> {

    @UiField
    HasValue<String> stringMeEditor;
    @UiField
    HasValue<Double> autoboxMeEditor;

    // boilerplate uibinder blabla
}

If I run this editor, either standalone or in a tree, I only receive a value for the string in the view, the double-box stays empty.

If I take the burden to write a LeafValueEditor, explicitely setting the values, in the setValue() method, the doubles appear.

So, where is the issue? Is the SimpleBeanEditorDriver not autobox-able and won't find the matching editor field?

UPDATE: The actual code has been asked for.

This is the actual editor. This editor works only, if the LeafValueEditor is in place. If the LVE is replaced by a simple "Editor", it will not present any value.

I know that there will be an issue with NPE if the value is null, but that can be managed with Validation.

package de.srs.pen.portal.widgets.metadataeditor;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.editor.client.LeafValueEditor;
import com.google.gwt.user.client.ui.IsWidget;

import de.srs.pen.api.meta.xml.PageClip;
import de.srs.pen.portal.widgets.editors.HasDeleteHandlers;
import de.srs.pen.portal.widgets.utils.HasActivity;

public interface PageClipEditor
        extends Activity
{
    public interface View
            extends IsWidget, HasActivity<PageClipEditor>, LeafValueEditor<PageClip>, HasDeleteHandlers
    {

        void removeFromParent();

    }
}

This is the implementation of the View interface.

package de.srs.pen.portal.widgets.metadataeditor;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.HasClickHandlers;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.Widget;

import de.srs.pen.api.meta.xml.PageClip;
import de.srs.pen.portal.widgets.editors.EditorDeleteEvent;
import de.srs.pen.portal.widgets.editors.EditorDeleteEventHandler;

public class PageClipEditorView
        extends Composite
        implements PageClipEditor.View
{

    private static PageClipEditorViewUiBinder uiBinder = GWT.create( PageClipEditorViewUiBinder.class );

    interface PageClipEditorViewUiBinder
            extends UiBinder<Widget, PageClipEditorView>
    {}

    private PageClipEditor activity;

    @UiField
    HasClickHandlers btnDelete;

    @UiField
    @Path("id")
    HasValue<String> idEditor;
    @UiField
    @Path("display")
    PageDisplayEnumEditor displayEditor;
    @UiField
    @Path("xPos")
    HasValue<Double> xPosEditor;
    @UiField
    @Path("yPos")
    HasValue<Double> yPosEditor;
    @UiField
    @Path("height")
    HasValue<Double> heightEditor;
    @UiField
    @Path("width")
    HasValue<Double> widthEditor;

    public PageClipEditorView() {
        initWidget( uiBinder.createAndBindUi( this ) );
    }

    @Override
    public void setActivity(PageClipEditor activity) {
        this.activity = activity;
    }

    @Override
    public PageClipEditor getActivity() {
        return this.activity;
    }

    @Override
    public HandlerRegistration addDeleteHandler(EditorDeleteEventHandler handler) {
        return addHandler( handler, EditorDeleteEvent.TYPE );
    }

    @UiHandler("btnDelete")
    public void handleDelete(ClickEvent ev) {
        fireEvent( new EditorDeleteEvent() );
    }

    @Override
    public void setValue(PageClip value) {
        displayEditor.asEditor().setValue( value.getDisplay() );
        heightEditor.setValue( value.getHeight() );
        widthEditor.setValue( value.getWidth() );
        xPosEditor.setValue( value.getxPos() );
        yPosEditor.setValue( value.getyPos() );
        idEditor.setValue( value.getId() );
    }

    @Override
    public PageClip getValue() {
        PageClip clip = new PageClip( idEditor.getValue(),
                                      xPosEditor.getValue(), yPosEditor.getValue(),
                                      widthEditor.getValue(), heightEditor.getValue(),
                                      displayEditor.asEditor().getValue() );
        return clip;
    }
}

This is the uibinder template file.

<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
    xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:p="urn:import:de.srs.pen.portal.widgets.metadataeditor">
    <ui:with type="de.srs.pen.portal.widgets.metadataeditor.MetadataEditorText"
        field="res" />
    <ui:with type="de.srs.pen.portal.widgets.icons.WidgetIcons"
        field="icon" />

    <ui:style>

    </ui:style>
    <g:HTMLPanel>
        <g:Image ui:field="btnDelete" resource="{icon.circleCloseDeleteGlyph}"
            height="16px" width="16px" title="{res.pageclipDelete}" />
        <g:InlineLabel text="{res.pageclipName}" />
        <g:TextBox ui:field="idEditor" width="5em"/>
        <g:InlineLabel text="{res.pageclipDisplay}" />
        <p:PageDisplayEnumEditor ui:field="displayEditor" />
        <g:InlineLabel text="{res.pageclipXPos}" />
        <g:DoubleBox ui:field="xPosEditor" width="2.5em" />
        <g:InlineLabel text="{res.pageclipYPos}" />
        <g:DoubleBox ui:field="yPosEditor" width="2.5em" />
        <g:InlineLabel text="{res.pageclipHeight}" />
        <g:DoubleBox ui:field="heightEditor" width="2.5em" />
        <g:InlineLabel text="{res.pageclipWidth}" />
        <g:DoubleBox ui:field="widthEditor" width="2.5em" />
    </g:HTMLPanel>
</ui:UiBinder> 

And finally, this is the PageClip Object itself.

package de.srs.pen.api.meta.xml;

import java.io.Serializable;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "clip", namespace = "urn:srs.pdx.metadata")
public class PageClip implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 5556156665068106790L;

    @XmlAttribute(required=true)
    protected String id;

    @XmlAttribute(name = "xPos", required = true)
    protected double xPos;

    @XmlAttribute(name = "yPos", required = true)
    protected double yPos;

    @XmlAttribute(name = "width", required = true)
    protected double width;

    @XmlAttribute(name = "height", required = true)
    protected double height;

    @XmlAttribute(name ="display", required = false)
    protected String display;

    public PageClip() {
    }

    public PageClip( String id, double xPos, double yPos, double width, double height ) {
        super();
        this.id = id;
        this.xPos = xPos;
        this.yPos = yPos;
        this.width = width;
        this.height = height;
    }

    public PageClip( String id, double xPos, double yPos, double width, double height, String display ) {
        this(id, xPos, yPos, width, height);
        this.display = display;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public double getxPos() {
        return xPos;
    }

    public void setxPos(double xPos) {
        this.xPos = xPos;
    }

    public double getyPos() {
        return yPos;
    }

    public void setyPos(double yPos) {
        this.yPos = yPos;
    }

    public double getWidth() {
        return width;
    }

    public void setWidth(double width) {
        this.width = width;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getDisplay() {
        return display;
    }

    public void setDisplay(String display) {
        this.display = display;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append( "PageClip [id=" )
            .append( id )
            .append( ", xPos=" )
            .append( xPos )
            .append( ", yPos=" )
            .append( yPos )
            .append( ", width=" )
            .append( width )
            .append( ", height=" )
            .append( height )
            .append( ", display=" )
            .append( display )
            .append( "]" );
        return builder.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((display == null) ? 0 : display.hashCode());
        long temp;
        temp = Double.doubleToLongBits( height );
        result = prime * result + (int)(temp ^ (temp >>> 32));
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        temp = Double.doubleToLongBits( width );
        result = prime * result + (int)(temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits( xPos );
        result = prime * result + (int)(temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits( yPos );
        result = prime * result + (int)(temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if( this == obj ) {
            return true;
        }
        if( obj == null ) {
            return false;
        }
        if( !(obj instanceof PageClip) ) {
            return false;
        }
        PageClip other = (PageClip)obj;
        if( display == null ) {
            if( other.display != null ) {
                return false;
            }
        }
        else if( !display.equals( other.display ) ) {
            return false;
        }
        if( Double.doubleToLongBits( height ) != Double.doubleToLongBits( other.height ) ) {
            return false;
        }
        if( id == null ) {
            if( other.id != null ) {
                return false;
            }
        }
        else if( !id.equals( other.id ) ) {
            return false;
        }
        if( Double.doubleToLongBits( width ) != Double.doubleToLongBits( other.width ) ) {
            return false;
        }
        if( Double.doubleToLongBits( xPos ) != Double.doubleToLongBits( other.xPos ) ) {
            return false;
        }
        if( Double.doubleToLongBits( yPos ) != Double.doubleToLongBits( other.yPos ) ) {
            return false;
        }
        return true;
    }


}
1
Did you try to set @Path("autoboxMe") to autoboxMeEditor ? Because your bean and your view don't have the same name for the fields. - Philippe Gonday
The editor framework supports finding the widget with the property and propertyEditor names. And the string value is properly set, so that cannot be a reason. But yes: I tried also with @Path set - no difference. - thst

1 Answers

1
votes

Yes, autoboxing is supported, though you should be very careful that it is actually what you want - if the autoBoxMeEditor.getValue() returns null, there will be a NullPointerException when you call driver.flush().

With that said, HasValue is not an editor, and your 'bean' has no getters and setters - these two facts should mean that none of your editor should work, instead of only the string. If you update the question with the real code, I will check back later.


From your edit:

This is the actual editor. This editor works only, if the LeafValueEditor is in place. If the LVE is replaced by a simple "Editor", it will not present any value.

This is the problem, and this is why it appears to work without actually saying that your subeditors are Editors:

@Override
public void setValue(PageClip value) {
    displayEditor.asEditor().setValue( value.getDisplay() );
    heightEditor.setValue( value.getHeight() );
    widthEditor.setValue( value.getWidth() );
    xPosEditor.setValue( value.getxPos() );
    yPosEditor.setValue( value.getyPos() );
    idEditor.setValue( value.getId() );
}

You should not have to write that method, but since a) you are not referring to your editors as Editors, and b) you are making the parent a LeafValueEditor, you must.

First, what does LeafValueEditor mean? In short, your type is saying "I represent some leaf in the editing tree - do not bother to look at my children (i.e. fields) to figure out how to bind sub-editors'. If you had instead actually implemented Editor<PageClip>, the editor system would have looked at the class, and tried to find any editor fields.

Next, since you don't have any editor fields, moving to Editor doesn't help! Instead of referring to your fields as HasValue, refer to them by their real type. This includes the interface LeafValueEditor (remember this from above?), so the String and the double will be bound correctly.


One possible future issue you are going to hit, since you didn't share the code of the driver setup: Make certain that you reference the editor implementation in the driver declaration, not the view interface. You must do this so that the driver knows which impl it is talking to, and what sub-fields (and such, sub-editors) it is expected to have.