2014-10-21 4 views
1

Мы совместно разрабатываем веб-приложение GWT, которое уже имеет рабочие вызовы RPC для других модулей. Мы построили новый модуль RPC (на основе существующей архитектуры), которая компилируется и работает, но терпит неудачу бросает исключение времени выполнения на следующей строке:Отложенная привязка GWT RPC не удалась

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

Последняя строка в консоли «Uncaught исключение убежали» затем трассировки стека в GWT.create() линии выше, который предшествует сообщение об ошибке: консоль

Deferred ошибка привязки для ... ожидать последующих неудач [ERROR]

Перед этими двумя литий определяет список прачечного красных ошибок, который начинается следующим образом:

[INFO] [(...)] - модуль ... был загружен

[DEBUG] [(...)] - Пересвязывание (...) DashboardService

[DEBUG] [(...)] -. Вызывающий генератор com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator

[DEBUG] [(...)] - Создание клиентского прокси-сервера для удаленного сервисного интерфейса '(...). DashboardService'

[INFO] [(...)] - Проверка аргумента типа 0 типа «java.util.Arrays.ArrayList», поскольку он отображается как массив с максимальным размером 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); 
    } 
} 

У нас есть двойные и triple проверил наш код RPC на точность, основанную на documentation, и предложения по SO, такие как проверка правильности подписи методов на всех интерфейсах и реализациях. Что-нибудь, очевидно, ошибочно выпрыгивает никому? Есть ли способ, чтобы мы могли отлаживать эту ошибку более подробно?

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

Является ли «канал» сериализуемым? Не похоже. Поле «Итератор» тоже выглядит для меня. Не похоже, что реализация, возвращаемая 'ArrayList', сериализуема ... Чтобы быстро определить ошибку, попробуйте простой тип возврата для' getChannelSummary'. «Строка» или «Целое число» - просто чтобы выяснить, неправильно ли настроена сама служба или это тип возврата. –

+5

* Остановить * аннулирование ваших сообщений. – ArtOfCode

+4

Что говорит @ArtOfCode. Это совершенно бесполезно - мода собирается вмешаться, убрать вашу способность уничтожать ваши вещи, и все будет восстановлено. Вопрос только в том, сколько людей придется очищать из-за вашего глупого вздоха –

ответ

1

Виновником является наиболее возможно DashboardChannelSummary. Разумеется, измените тип возврата getChannelSummary на что-то «безопасное», например String или просто Void. Если ошибка повторяется, возникает проблема с конфигурацией службы (хотя я сомневаюсь, что она возникнет на этапе компиляции GWT). Если эта служба работает, вы можете быть уверены, что это связано с тем, что DashboardChannelSummary не является сериализуемым.

Хотя сам класс имеет конструктор no-args и реализует IsSerializable, не все поля являются сериализуемыми. Вы должны поближе ознакомиться с классом Channel (возможно, DocumentSummary тоже, но в этом вопросе нет кода), а поля Iterator (ArrayList возвращает экземпляр Itr, который, похоже, не сериализуется).

Если ошибка по-прежнему сохраняется, попробуйте упростить DashboardChannelSummary, пока не получите рабочую версию, а затем выполните свой путь вверх, пока не найдете часть, вызывающую ошибку.