2014-10-21 99 views
1

我們正在共同開發一個GWT Web應用程序,該應用程序已經對其他模塊進行了RPC調用。我們建立了編譯和運行,但沒有對下面的行拋出一個運行時異常的新的RPC模塊(基於現有的架構):GWT RPC延遲綁定失敗

this.dashboardService = GWT.create(DashboardService.class); 

在控制檯的最後一行是「未捕獲的異常逃脫」接着堆棧跟蹤上述GWT.create()線,這是由在控制檯錯誤消息之前:

延遲綁定失敗...期望後續故障[ERROR]

這兩個立之前網元是一個紅色錯誤細目清單開頭如下:

[INFO] [(...)] - 模塊...已被加載

[DEBUG] [(...)] - 重新綁定(...)DashboardService

[DEBUG] [(...)] - 調用發電機com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator

[DEBUG] [(... )] - 生成遠程服務接口的客戶端代理'(...)。DashboardService'

[INFO] [(...)] - 檢查類型爲「java.util.Arrays.ArrayList」的參數0,因爲它在此類型或其子類型中的最大維數爲1的數組中暴露(通過。)。DashboardChannelSummary)

。 。 。 (沒有堆棧跟蹤或行號的更多錯誤)

控制檯詢問「您忘了繼承模塊嗎?但基於我的研究,這不是問題;該問題在GWT延遲綁定進程中的某處,這在堆棧跟蹤中不可見。我懷疑上面的粗體行是問題,但是我不能在沒有行號的情況下使這個錯誤信息成爲頭條或故事。下面是與替換專有包/模塊名稱(...)的代碼:

的web.xml

<servlet> 
    <servlet-name>(...) DashboardService 
    </servlet-name> 
    <servlet-class>(...).server.DashboardServiceImpl 
    </servlet-class> 
</servlet> 

<servlet-mapping> 
    <servlet-name>(...) DashboardService 
    </servlet-name> 
    <url-pattern>/(...)/DashboardService</url-pattern> 
</servlet-mapping> 

DashboardChannelSummary.java

/** 
* This class is an in memory representation of the results of a document search 
*/ 
public class DashboardChannelSummary implements IsSerializable { 
    /** Only searches for documents from the past in this amount (the past week) */ 
    private static final int DEFAULT_DASHBOARD_HISTORY_IN_DAYS = -7; 
    /** array of channels */ 
    private List<Channel> channels; 
    /** iterator */ 
    private Iterator<Channel> iterator; 
    /** */ 
    private final static String IMAGE_PATH = "/images/channels/"; 
    /** */ 
    private final static String IMAGE_EXT = ".png"; 
    /** constant for the channel header name */ 
    public final static String BUSINESS_LABEL = "business aviation"; 
    /** constant for the channel header name */ 
    public final static String COMMERCIAL_LABEL = "commercial aviation"; 
    /** constant for the channel header name */ 
    public final static String MRO_LABEL = "mro"; 
    /** constant for the channel header name */ 
    public final static String DEFENSE_LABEL = "defense"; 
    /** 
    * 
    */ 
    public enum CHANNEL_NAME { 
     BUSINESS (BUSINESS_LABEL, DocumentSummary.BA_ID), 
     COMMERCIAL (COMMERCIAL_LABEL, DocumentSummary.CA_ID), 
     MRO  (MRO_LABEL,  DocumentSummary.MRO_ID), 
     DEFENSE (DEFENSE_LABEL, DocumentSummary.DEFENSE_ID); 
     /** */ 
     public String label; 
     /** */ 
     public int ID; 
     /** */ 
     private CHANNEL_NAME(String label, int ID) { 
      this.label = label.toUpperCase(); 
      this.ID = ID; 
     } 
    }; 

    /** 
    * 
    */ 
    public static List<String> channelNames() { 
     ArrayList<String> channels = new ArrayList<String>(CHANNEL_NAME.values().length); 
     for(int i=0; i<channels.size(); i++) { 
      channels.add(CHANNEL_NAME.values()[i].label); 
     } 
     return channels; 
    } 

    /** 
    * 
    */ 
    public static int[] channelIDs() { 
     int[] IDs = new int[CHANNEL_NAME.values().length]; 
     for(int i=0; i<IDs.length; i++) { 
      IDs[i] = CHANNEL_NAME.values()[i].ID; 
     } 
     return IDs; 
    } 

    /** 
    * 
    * @return 
    */ 
    public static int channelCount() { 
     return CHANNEL_NAME.values().length; 
    } 

    /** 
    * 
    */ 
    public static Date cutoffDate() { 
     Date date = new Date(0); 
     CalendarUtil.addDaysToDate(date, DEFAULT_DASHBOARD_HISTORY_IN_DAYS); 
     return date; 
    } 

    /** 
    * 
    */ 
    public class Channel { 
     /** the name of this channel */ 
     private CHANNEL_NAME name; 
     /** The list of documents */ 
     private List<DocumentSummary> docs; 
     /** the iterator */ 
     private Iterator<DocumentSummary> iterator; 

     /** 
     * 
     */ 
     public Channel(List<DocumentSummary> docs, CHANNEL_NAME name) { 
      this.docs = docs; 
      this.name = name; 
      iterator = docs.iterator(); 
     } 

     /** 
     * 
     */ 
     public String getLabel() { 
      return name.label; 
     } 

     /** 
     * 
     */ 
     public List<DocumentSummary> getDocuments() { 
      return docs; 
     } 

     /** 
     * 
     */ 
     public boolean hasDocuments() { 
      return iterator.hasNext(); 
     } 

     /** 
     * 
     * @return 
     */ 
     public DocumentSummary nextDocument() { 
      if(iterator.hasNext()) { 
       return iterator.next(); 
      } 
      else { 
       return null; 
      } 
     } 

     /** 
     * 
     */ 
     public String nextImageURL() { 
      return GWT.getHostPageBaseURL().concat(IMAGE_PATH + String.valueOf(Random.nextInt(channels.size()) - 1) + IMAGE_EXT); 
     } 
    } 

    /** 
    * Constructor 
    */ 
    public DashboardChannelSummary() { 
     channels = new ArrayList<Channel>(CHANNEL_NAME.values().length); 
     iterator = channels.iterator(); 
    } 

    /** 
    * Constructor 
    */ 
    public DashboardChannelSummary(List<List<DocumentSummary>> channelList) { 
     channels = new ArrayList<Channel>(CHANNEL_NAME.values().length); 
     iterator = channels.iterator(); 
     int count = 0; 
     for(List<DocumentSummary> channelData : channelList) 
     { 
      channels.add(new Channel(channelData, CHANNEL_NAME.values()[count++])); 
     } 
    } 

    /** 
    * @return 
    */ 
    public List<Channel> getChannels() { 
     return channels; 
    } 

    /** 
    * @return 
    */ 
    public Channel getChannel(int channel) { 
     return channels.get(channel); 
    } 

    /** 
    * @return 
    */ 
    public Channel nextChannel() { 
     if(iterator.hasNext()) { 
      return iterator.next(); 
     } 
     else { 
      return null; 
     } 
    } 

    /** 
    * @return 
    */ 
    public List<DocumentSummary> getDocuments(int channel) { 
     return this.getChannel(channel).getDocuments(); 
    } 
} 

DashboardPresenter.java :

private final DashboardServiceAsync dashboardService; 

和延遲綁定,在構造失敗:

this.dashboardService = GWT.create(DashboardService.class);

DashboardServiceAsync。Java的:

public interface DashboardServiceAsync { 

    /** 
    * 
    * @param channelIDs 
    * @param startDate 
    * @param async 
    */ 
    void getChannelSummary(int[] channelIDs, Date startDate, AsyncCallback<DashboardChannelSummary> async); 
} 

DashboardService.java:

@RemoteServiceRelativePath("DashboardService") public interface DashboardService extends RemoteService { 

    /** 
    * 
    * @param channelIDs 
    * @param startDate 
    * @return 
    */ 
    DashboardChannelSummary getChannelSummary(int[] channelIDs, Date startDate); 
} 

在服務器上:

DashboardServiceImpl.java:

public class DashboardServiceImpl extends RemoteServiceServlet implements DashboardService { 

    /** 
    * 
    * @param channelIDs 
    * @param startDate 
    * @return 
    */ 
    @Override 
    public DashboardChannelSummary getChannelSummary(int[] channelIDs, Date startDate) { 
     return new DashboardDaoImpl().getChannelSummary(channelIDs, startDate); 
    } 
} 

我們有雙人和三重基於這樣documentation和建議,如確保方法簽名是在所有接口和實現正確的檢查我們的RPC代碼的準確性。任何明顯錯誤跳出去的人?有沒有一種方法可以讓我們更詳細地調試這個錯誤?

UPDATE

DashboardChannelSummary.java從服務器傳輸數據到客戶端重新設計,最大效率,與所有屬性現在「序列化:」

/** 
* This class is an in memory representation of the results of a document search. 
*/ 
public class DashboardChannelSummary implements IsSerializable { 
    /** Only searches for documents from the past in this amount (the past week) */ 
    private static final int DEFAULT_DASHBOARD_HISTORY_IN_DAYS = -7; 
    /** array of channels */ 
    private ArrayList<ArrayList<DocumentSummary>> channels; 
    /** */ 
    private int channel = 0; 
    /** */ 
    private int image = 0; 
    /** */ 
    private int index = 0; 
    /** */ 
    private int last = 0; 
    /** */ 
    private final static String IMAGE_PATH = "images/channels/"; 
    /** */ 
    private final static String IMAGE_EXT = ".jpg"; 
    /** constant for the channel header name */ 
    public final static String BUSINESS_LABEL = "business"; 
    /** constant for the channel header name */ 
    public final static String COMMERCIAL_LABEL = "commercial"; 
    /** constant for the channel header name */ 
    public final static String MRO_LABEL = "mro"; 
    /** constant for the channel header name */ 
    public final static String DEFENSE_LABEL = "defense"; 
    /** 
    * 
    */ 
    public enum CHANNEL_NAME { 
     BUSINESS (BUSINESS_LABEL, DocumentSummary.BA_ID,  "bus"), 
     COMMERCIAL (COMMERCIAL_LABEL, DocumentSummary.CA_ID,  "_com"), 
     MRO  (MRO_LABEL,  DocumentSummary.MRO_ID,  "mro"), 
     DEFENSE (DEFENSE_LABEL, DocumentSummary.DEFENSE_ID, "mil"); 
     /** */ 
     public String label; 
     /** */ 
     public int ID; 
     /** */ 
     public String prefix; 
     /** */ 
     private CHANNEL_NAME(String label, int ID, String prefix) { 
      this.label = label.toUpperCase(); 
      this.ID = ID; 
      this.prefix = prefix; 
     } 
    }; 

    /** 
    * 
    */ 
    private String nextRandomImage() { 
     while(index == last) { 
      index = Random.nextInt(channels.size()) + 1; 
     } 
     last = index; 
     return String.valueOf(index); 
    } 

    /** 
    * 
    */ 
    public static List<String> channelNames() { 
     ArrayList<String> channels = new ArrayList<String>(CHANNEL_NAME.values().length); 
     for(int i=0; i<channels.size(); i++) { 
      channels.add(CHANNEL_NAME.values()[i].label); 
     } 
     return channels; 
    } 

    /** 
    * 
    */ 
    public static int[] channelIDs() { 
     int[] IDs = new int[CHANNEL_NAME.values().length]; 
     for(int i=0; i<IDs.length; i++) { 
      IDs[i] = CHANNEL_NAME.values()[i].ID; 
     } 
     return IDs; 
    } 

    /** 
    * 
    * @return 
    */ 
    public static int channelCount() { 
     return CHANNEL_NAME.values().length; 
    } 

    /** 
    * 
    */ 
    public static Date cutoffDate() { 
     Date date = new Date(); 
     CalendarUtil.addDaysToDate(date, DEFAULT_DASHBOARD_HISTORY_IN_DAYS); 
     return date; 
    } 


    /** 
    * Constructor 
    */ 
    public DashboardChannelSummary() { 
    } 

    /** 
    * Constructor 
    */ 
    public DashboardChannelSummary(ArrayList<ArrayList<DocumentSummary>> channels) { 
     this.channels = channels; 
    } 

    /** 
    * 
    */ 
    public String nextImageURL() { 
     if(++image > channels.get(channel - 1).size()) { 
      image = 0; 
     } 
     return GWT.getHostPageBaseURL() + 
       IMAGE_PATH + 
       CHANNEL_NAME.values()[channel - 1].prefix + 
       nextRandomImage() + 
       IMAGE_EXT; 
    } 

    /** 
    * 
    */ 
    public ArrayList<DocumentSummary> nextChannel() { 
     return channels.get(channel++); 
    } 

    /** 
    * 
    */ 
    public String toString() { 
     return this.getClass().toString() + " current channel : " + channel; 
    } 
} 
+0

是'Channel'序列化?看起來不像。 'Iterator'字段也適合我。它看起來並不像用'ArrayList'是序列化所返回的執行...要快速查明錯誤 - 嘗試'getChannelSummary'一個簡單的返回類型。 'String'或'Integer' - 只是爲了找出服務本身是否被錯誤配置或者是返回類型。 – 2014-10-21 21:22:58

+5

*停止*破壞你的帖子。 – ArtOfCode 2016-04-09 20:36:13

+4

@ArtOfCode說什麼。這完全是徒勞 - 一個國防部將會介入,拿走你破壞你的東西的能力,並且一切都會恢復。唯一的問題是,由於你的愚蠢橫衝直撞,有多少人需要清理 – 2016-04-09 20:37:11

回答

1

罪魁禍首是最可能是DashboardChannelSummary。可以肯定的getChannelSummary返回類型更改爲「安全」的,像String或只是Void。如果錯誤仍然存​​在,有一個與該服務的配置出現問題(不過,我懷疑在GWT的編譯階段將拿出)。如果這個服務有效,那麼你可以肯定的是,這是因爲DashboardChannelSummary不是可序列化的。

雖然類本身有一個無參數的構造函數,並實現IsSerializable,不是所有的領域都是可序列化。您應該仔細看看Channel類(也許是DocumentSummary,但沒有代碼在問題中提供)和Iterator字段(ArrayList返回Itr實例,似乎不可序列化)。

如果錯誤仍然存​​在,請嘗試簡化DashboardChannelSummary,直到獲得工作版本,然後按照「上」的方式工作,直至找到導致錯誤的部分。