title: GWT ListEditor implementing HasEditorErrors, custom error marking for ListEditor
body: <p>I have this ListEditor that takes care of editing the licenses for a Customer. In my <code>CustomerEditor</code>, thie <code>LicensesEditor</code> is bound to path licenses, which is of type <code>List&lt;License&gt;&gt;</code>.</p>
  
  <blockquote>
    <p>Customer (1)--> (many) Licenses (java.util.List)</p>
  </blockquote>
  
  <p>Now, the validation rules state that at least one license per Customer is required. The constraint violations work perfectly. But how do I implement HasEditorErrors for a ListEditor ...  I want to provide my own error marking.</p>
  
  <p><strong>What type do I inject for the generic parameter T of HasEditorErrors &lt; T ></strong> ??</p>
  
  <pre><code>public interface HasEditorErrors&lt;T&gt; extends Editor&lt;T&gt;
  </code></pre>
  
  <p>The signature for the ListEditor is as follows ...</p>
  
  <pre><code>public class LicensesEditor extends Composite implements IsEditor&lt;ListEditor&lt;License, LicenseInListEditor&gt;&gt;
  </code></pre>
  
  <p>I tried to implement <code>HasEditorErrors&lt;List&lt;License&gt;&gt;</code> which gives at runtime the error :</p>
  
  <blockquote>
    <p>[DEBUG] [klawtapp] - Descending into licenses
    [ERROR] [klawtapp] - Could not find a getter for path  editor in proxy type java.util.List</p>
  </blockquote>
  
  <p>If I implement <code>HasEditorErrors&lt;LicensesEditor&gt;</code></p>
  
  <blockquote>
    <p>[ERROR] [klawtapp] Could not find a getter for path editor in proxy
    type com.klawt.screen.ui.customers.LicensesEditor</p>
  </blockquote>
  
  <p>Keeping a question mark in HasEditorErrors as implemented interface gives compile time error :</p>
  
  <blockquote>
    <p>The type LicensesEditor cannot extend or implement HasEditorErrors.
    A supertype may not specify any wildcard  LicensesEditor.java</p>
  </blockquote>
  
  <p>Anybody ?</p>
  
  <p><em>UPDATE,full code below :</em></p>
  
  <pre><code>public class LicensesEditor extends Composite implements IsEditor&lt;ListEditor&lt;License, LicenseInListEditor&gt;&gt; {
  
      @UiField
      Image validationErrorIcon;
  
      interface LicensesEditorUiBinder extends UiBinder&lt;Widget, LicensesEditor&gt; {
      }
  
      private static LicensesEditorUiBinder uiBinder = GWT.create(LicensesEditorUiBinder.class);
  
      @UiField
      VerticalPanel container;
  
      ListEditor&lt;License, LicenseInListEditor&gt; editor;
  
      public LicensesEditor() {
          initWidget(uiBinder.createAndBindUi(this));
          editor = ListEditor.of(new LicenseInListEditorSource());
          clearErrors();
      }
  
      @Override
      public ListEditor&lt;License, LicenseInListEditor&gt; asEditor() {
          return editor;
      }
  
      public void addLicense(License emailAddress) {
          editor.getList().add(emailAddress);
          if (emailAddress.getAdministrator()) {
              setPrimary(editor.getList().size() - 1);
          }
      }
  
      public void remove(int index) {
          editor.getList().remove(index);
      }
  
      public void update(int index, License emailAddress) {
          editor.getList().remove(index);
          editor.getList().add(index, emailAddress);
      }
  
      /**
       * make the phonenumber at the index the primary phonenumber and the other
       * phone numbers not primary.
       * 
       * @param index
       */
      public void setPrimary(int index) {
          int loop = 0;
  
          for (License emailAddress : Collections.unmodifiableList(editor.getList())) {
              emailAddress.setAdministrator(index == loop);
              update(loop, emailAddress);
              loop++;
          }
      }
  
      private class LicenseInListEditorSource extends EditorSource&lt;LicenseInListEditor&gt; {
  
          @Override
          public LicenseInListEditor create(final int index) {
              LicenseInListEditor editor = new LicenseInListEditor();
              editor.addDeleteHandler(new ListEditorDeleteEventHandler() {
                  @Override
                  public void onEditorEvent(ListEditorDeleteEvent event) {
                      remove(index);
                  }
              });
              editor.addUpdateHandler(new EditorUpdateEventHandler() {
                  @Override
                  public void onEditorUpdate(EditorUpdateEvent event) {
                      License emailAddress = (License) event.getUpdated();
                      update(index, emailAddress);
                      if (emailAddress.getAdministrator()) {
                          setPrimary(index);
                      }
                  }
              });
              container.insert(editor, index);
              updateOddEven();
              return editor;
          }
  
          @Override
          public void dispose(LicenseInListEditor subEditor) {
              container.remove(subEditor);
              updateOddEven();
          }
  
          @Override
          public void setIndex(LicenseInListEditor editor, int index) {
              container.insert(editor, index);
              updateOddEven();
          }
  
          public void updateOddEven() {
              for (int widgetIndex = 0; widgetIndex &lt; container.getWidgetCount(); widgetIndex++) {
                  container.getWidget(widgetIndex).setStyleName(KlawtResources.INSTANCE.form().listEditorEven(),
                          (widgetIndex % 2 == 0));
                  container.getWidget(widgetIndex).setStyleName(KlawtResources.INSTANCE.form().listEditorOdd(),
                          (widgetIndex % 2 == 1));
              }
          }
  
      }
  
      // @Override
      // public void showErrors(List&lt;EditorError&gt; errors) {
      // StringBuilder sb = new StringBuilder();
      // int errorCount = 0;
      // for (EditorError editorError : errors) {
      // if (errorCount &gt; 0) {
      // sb.append("\n");
      // }
      // errorCount++;
      // sb.append(editorError.getMessage());
      // }
      // if (errorCount == 0) {
      // clearErrors();
      // } else {
      // container.setStyleName(KlawtResources.INSTANCE.form().formError(), true);
      // validationErrorIcon.setVisible(true);
      // validationErrorIcon.setTitle(sb.toString());
      // }
      // }
  
      private void clearErrors() {
          container.setStyleName(KlawtResources.INSTANCE.form().formError(), false);
          validationErrorIcon.setVisible(false);
          validationErrorIcon.setTitle("");
      }
  
  }
  </code></pre>