【问题标题】:GWT RPC Deferred Binding FailedGWT RPC 延迟绑定失败
【发布时间】:2014-12-17 05:56:23
【问题描述】:

我们正在共同开发一个 GWT Web 应用程序,该应用程序已经为其他模块提供了有效的 RPC 调用。我们构建了一个新的 RPC 模块(基于现有架构),它可以编译并运行,但无法在以下行抛出运行时异常:

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

控制台的最后一行是“Uncaught exception escaped”,然后是上面GWT.create()行的堆栈跟踪,前面是控制台错误消息:

延迟绑定失败...预期后续失败 [错误]

在这两行之前是一个红色错误清单,开头如下:

[INFO] [(...)] - 模块 ... 已加载

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

[DEBUG] [(...)] - 调用生成器 com.google.gwt.user.rebind.rpc.ServiceInterfaceProxyGenerator

[DEBUG] [(...)] - 为远程服务接口'(...).DashboardService'生成客户端代理

[INFO] [(...)] - 检查 'java.util.Arrays.ArrayList' 类型的类型参数 0,因为它在此类型中公开为最大维度为 1 或 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 和关于 SO 的建议对我们的 RPC 代码的准确性进行了两次和三次检查,例如确保方法签名在所有接口和实现中都是正确的。向任何人跳出来有什么明显的错误吗?有没有办法可以更详细地调试此错误?

更新

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;
    }
}

【问题讨论】:

  • Channel 是否可序列化?看起来不像。 Iterator 字段在我看来也很可疑。看起来 ArrayList 返回的实现不是可序列化的...为了快速查明错误 - 尝试使用 getChannelSummary 的简单返回类型。 StringInteger - 只是为了找出服务本身是否以某种方式错误配置或者它是返回类型。
  • 停止破坏你的帖子。
  • @ArtOfCode 所说的。这完全是徒劳的——一个模组会介入,夺走你破坏东西的能力,一切都会恢复。唯一的问题是有多少人会因为你愚蠢的横冲直撞而不得不清理

标签: java eclipse generics gwt gwt-rpc


【解决方案1】:

罪魁祸首很可能是DashboardChannelSummary。可以肯定的是,将getChannelSummary 的返回类型更改为“安全”类型,例如String 或只是Void。如果错误仍然存​​在,则服务的配置存在问题(不过,我怀疑它会在 GWT 的编译阶段出现)。如果此服务有效,那么您可以确定这是因为 DashboardChannelSummary 不可序列化。

虽然类本身具有无参数构造函数并实现IsSerializable,但并非所有字段都是可序列化的。您应该仔细查看Channel 类(也可能是DocumentSummary,但问题中没有提供它的代码)和Iterator 字段(ArrayList 返回一个Itr 实例,它没有' t 似乎是可序列化的)。

如果错误仍然存​​在,请尝试简化DashboardChannelSummary,直到获得一个工作版本,然后“向上”工作,直到找到导致错误的部分。

【讨论】:

    猜你喜欢
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-12
    • 2013-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多