OData4j异常 - “奇数字符数”和“错误的valueString部分keyString”

时间:2012-02-09 08:12:15

标签: wcf json datetime illegalargumentexception odata4j

修改

解决方案是创建一个镜像相关表的视图,并将日期转换为varchar,然后使用匹配的排序规则将其转换回日期

END OF EDIT

任何人都可以告诉我为什么OData4j从我的一个WCF数据服务服务器读取日期时间值很好但是当从另一个WCF数据服务读取具有相同格式的完全相同的日期时间类型时,会遇到非法的参数异常(作为keyString的一部分的错误的valueString) ?

  

java.lang.IllegalArgumentException:错误的valueString   [datetime'2012-01-24T14%3A57%3A22.243']作为keyString的一部分

另一个问题是,当我从OData4j读取日期时间类型没有问题的服务请求JSON响应时,我得到另一个非法参数异常,错误消息是 - 奇数个字符。

  

java.lang.IllegalArgumentException异常:   org.odata4j.repack.org.apache.commons.codec.DecoderException:奇怪   字符数。

由于WCF数据服务不能有多个源,我已经为每个自己的实体数据模型源(来自现有数据库)创建了2个项目。就像我上面提到的,我遇到了这些烦人的错误。

总结......

示例1:作为keyString一部分的错误valueString - 在读取datetime时。 FormatType.JSON也会发生。

ODataConsumer customerInfoServices = ODataConsumer
                                     .newBuilder("http://10.0.2.2:41664/CustomerInfoWCFDataServices.svc/")
                                     .setFormatType(FormatType.ATOM)
                                     .build();

customer = customerInfoServices
           .getEntities("Customers")
           .select("name, id")
           .filter("id eq " + 5)
           .execute()
           .firstOrNull();

示例2:奇数个字符。仅与FormatType.JSON一起发生,并且在阅读日期时间方面没有问题。

ODataConsumer businessServices = ODataConsumer
                                 .newBuilder("http://10.0.2.2:35932/BusinessWCFDataServices.svc/")
                                 .setFormatType(FormatType.JSON)
                                 .build();

Enumerable<?> ordrer = businessServices
                       .getEntities("Orders")
                       .filter("custId eq " + customer.getProperty("id").getValue())
                       .execute();

我想要的是接收JSON响应(ATOM对于android来说仍然过于臃肿)并且没有读取日期时间属性的问题。


没有人能够帮助我?

我一直在试着在Google上找到一个解决方案,但没有任何运气。

没有日期时间问题的数据库上的排序规则是“Danish_Norwegian_CI_AS”,并且在读取错误的数据库上是“SQL_Danish_Pref_CP1_CI_AS”。我不知道这是否有任何意义,但我有一个悬念,它与它有关。

2 个答案:

答案 0 :(得分:0)

解决方案是创建一个镜像相关表的视图,并将日期转换为varchar,然后使用匹配的排序规则将其转换回日期。 : - )

答案 1 :(得分:0)

我今天遇到了这个问题,在跑了大约三个小时后谷歌搜索并查看代码我设法弄清楚发生了什么。这是我的设置/情况以及我发现的内容:

设置

  1. (OData服务)Windows Server 2012上的Microsoft IIS 8.0使用 默认应用程序池。
  2. (OData Producer)Microsoft WCF中间层 使用实体框架和Web数据服务。
  3. (OData Consumer) Android客户端使用OData4J v0.8 SNAPSHOT。
  4. 问题

    在我的中间层(OData Producer)中,我使用Entity Framework 5.0来定义一个带有Edm.DateTime列的简单表。我的MessageTable.edmx文件生成一个简单的表:

    CREATE TABLE [dbo].[MessageTable] (
        [Id] int IDENTITY(1,1) NOT NULL,
        [Date1] datetime NULL
    );
    

    在我的中间层的WCF数据服务(OData Producer)中,我从我的Android客户端应用程序拦截了OData POST。我使用一些C#代码手动设置中间层的Date1列:

        private static void ProcessMessage(ODataMessage message)
        {
            .
            .
            .
            conn.Open();
            cmd.ExecuteNonQuery();
            int returnCode = (int)cmd.Parameters["@result"].Value;
            if (returnCode == 0)
            {
                message.Processed = true;
                message.Date1 = DateTime.Now;
            }
            .
            .
            .
        }
    

    请注意,我使用了C#的DateTime.Now静态属性。 MSDN文档指出DateTime.Now

      

    获取一个DateTime对象,该对象在此计算机上设置为当前日期和时间,表示为本地时间

    要实现的关键是本地时间意味着C#日期时间结构现在包含本地时区信息。

    因此,在中间层代码完成后,WCF服务将OData POST插入到我的表中。然后Microsoft将[Date1]列发送回我的A​​ndroid客户端(OData Consumer)。看来Microsoft将日期编码为OData DateTimeOffset,因为它包含本地时区信息。即作为2013-08-26T17:30:00.0000000-7:00

    守则

    在OData4j中有一个包org.odata.internal来处理解析OData日期时间字符串。在0.6版本中,我在第40-44行找到了关于用于解析日期时间字符串的DATETIME_PATTERN正则表达式模式的以下注释:

    40   // Since not everybody seems to adhere to the spec, we are trying to be
    41   // tolerant against different formats
    42   // spec says:
    43   // Edm.DateTime: yyyy-mm-ddThh:mm[:ss[.fffffff]]
    44   // Edm.DateTimeOffset: yyyy-mm-ddThh:mm[:ss[.fffffff]](('+'|'-')hh':'mm)|'Z'
    45   private static final Pattern DATETIME_PATTERN =
    46       Pattern.compile("(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})(:\\d{2})?(\\.\\d{1,7})?((?:(?:\\+|\\-)\\d{2}:\\d{2})|Z)?");
    47 
    48
    

    在OData4j v0.7中,DATETIME_PATTERN已成为DATETIME_XML_PATTERN

    40 
    41   private static final Pattern DATETIME_XML_PATTERN = Pattern.compile("" +
    42       "^" +
    43       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})" + // group 1 (datetime)
    44       "(:\\d{2})?" + // group 2 (seconds)
    45       "(\\.\\d{1,7})?" + // group 3 (nanoseconds)
    46       "(Z)?" + // group 4 (tz, ignored - handles bad services)
    47       "$");
    48 
    49   private static final Pattern DATETIMEOFFSET_XML_PATTERN = Pattern.compile("" +
    50       "^" +
    51       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})" + // group 1 (datetime)
    52       "(\\.\\d{1,7})?" + // group 2 (nanoSeconds)
    53       "(((\\+|-)\\d{2}:\\d{2})|(Z))" + // group 3 (offset) / group 6 (utc)
    54       "$");
    

    我认为第46行的评论解释了一切:

      

    ... //组4(tz,忽略 - 处理不良服务)

    我将此解释为'任何时区信息都将被忽略 - 这会处理发送时区信息的错误服务(即Microsoft)

    在我看来,OData4j作者决定坚持使用他们的枪,只接受正确的Edm.DateTime字符串格式。

    解决方案

    如果您可以访问OData Producer代码,则修复非常简单:

        private static void ProcessMessage(ODataMessage message)
        {
            .
            .
            .
            conn.Open();
            cmd.ExecuteNonQuery();
            int returnCode = (int)cmd.Parameters["@result"].Value;
            if (returnCode == 0)
            {
                message.Processed = true;
                message.Date1 = DateTime.UtcNow;
            }
            .
            .
            .
        }
    

    请改用DateTime.UtcNow属性。 MSDN文档声明:

      

    获取一个DateTime对象,该对象在此计算机上设置为当前日期和时间,表示为协调世界时(UTC)

    如果您无权访问OData生产者,我能看到的唯一解决方案是更改OData4j代码。更改DATETIME_XML_PATTERN的正则表达式模式:

    41   private static final Pattern DATETIME_XML_PATTERN = Pattern.compile("" +
    42       "^" +
    43       "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})" + // group 1 (datetime)
    44       "(:\\d{2})?" + // group 2 (seconds)
    45       "(\\.\\d{1,7})?" + // group 3 (nanoseconds)
    46       "((?:(?:\\+|\\-)\\d{2}:\\d{2})|Z)?" + 
    47       "$");
    

    结论

    我认为这实际上是微软的一个错误。我确定他们有一些合理的发送Edm.DateTimeOffset,但我的MessageTable.edmx文件指定[Date1]Edm.DateTime,所以我认为Microsoft代码应该执行我转换为UTC,或抛出异常。一个例外会警告我,我使用了不正确的DateTime结构,并帮助我更快地看到DateTime.UtcNow解决方案。