Исключения OData4j - «Нечетное количество символов» и «неверная часть valueString keyString» - PullRequest
1 голос
/ 09 февраля 2012

РЕДАКТИРОВАТЬ:

Решение состояло в том, чтобы создать представление, которое зеркально отражает соответствующую таблицу и преобразовало дату в varchar, а затем преобразовать ее обратно в дату с соответствующим сопоставлением

КОНЕЦ РЕДАКТИРОВАНИЯ

Может кто-нибудь сказать мне, почему OData4j отлично считывает значения даты и времени с одного из моих серверов Службы данных WCF, но сталкивается с недопустимым исключением аргумента (неверное значение ValueString как часть keyString) при чтении точно такого же типа даты и времени с тем же форматом из другой службы данных WCF?

java.lang.IllegalArgumentException: bad valueString [datetime'2012-01-24T14% 3A57% 3A22.243 '] какчасть keyString

Другая проблема заключается в том, что когда я запрашиваю ответ JSON от службы, из которой у OData4j не было проблем при чтении типов datetime, я получаю еще одно недопустимое исключение аргумента, и сообщение об ошибке - нечетное числосимволов.

java.lang.IllegalArgumentException: org.odata4j.repack.org.apache.commons.codec.DecoderException: Нечетное количество символов.

Поскольку службы данных WCF не могут иметь несколько источников, я создал 2 проекта, каждый из которых имеет собственный источник модели данных сущностей (из существующей базы данных).И, как я упоминал выше, я получаю эти надоедливые ошибки.

В заключение ...

Пример 1: неверное значение valueString как часть keyString - при чтении 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 голосов
/ 28 августа 2013

Я столкнулся с этой проблемой сегодня, и после трех часов бегания по Google, глядя на код, мне удалось выяснить, что происходит. Вот мои настройки / ситуация и что я нашел:

Настройка

  1. (служба OData) Microsoft IIS 8.0 в Windows Server 2012 с использованием пул приложений по умолчанию.
  2. (OData Producer) Microsoft WCF среднего уровня используя Entity Framework и Web Data Services.
  3. (OData Consumer) Android-клиент, использующий OData4J v0.8 SNAPSHOT.

Проблема

В моем промежуточном уровне (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) я перехватываю OData POST из моего клиентского приложения Android. Я вручную установил столбец Date1 на среднем уровне, используя некоторый код C #:

    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] обратно на мой клиент Android (Потребитель OData). Похоже, что 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       "$");

Заключение

Я думаю, что это на самом деле ошибка со стороны Microsoft. Я уверен, что у них есть некоторые обоснования для отправки Edm.DateTimeOffset, но мой файл MessageTable.edmx указывает [Date1] как Edm.DateTime, поэтому я думаю, что код Microsoft должен либо выполнить преобразование в UTC для меня, либо бросить исключение. Исключение предупредило бы меня о том, что я использовал неправильную структуру DateTime, и помогло бы мне увидеть решение DateTime.UtcNow намного быстрее.

0 голосов
/ 09 марта 2012

Решение состояло в том, чтобы создать представление, отражающее данную таблицу и преобразовавшее дату в varchar, а затем преобразовать ее обратно в дату с соответствующим сопоставлением. : -)

...