Продление теста сериализации Wicket - PullRequest
5 голосов
/ 30 ноября 2011

Я работаю над большим Java-приложением, которое использует Wicket 1.5 вместе с Hibernate / JPA 2. У Wicket есть стандартное правило, согласно которому объекты, хранящиеся в сеансе, должны реализовывать Serializable.У нас есть дополнительное правило, согласно которому управляемые объекты JPA не должны храниться в сеансе.Вместо этого управляемые объекты JPA загружаются при каждом запросе через отсоединяемые модели.

Чтобы усложнить ситуацию, законно хранить объект Entity в сеансе при условии, что он еще не был сохранен.В результате, некоторые из наших классов уже реализуют Serializable.

Если бы я хотел расширить тест сериализации Wicket для обнаружения объектов, принадлежащих JPA, как бы я поступил?Это возможно без локальной развилки Wicket?

Ответы [ 3 ]

5 голосов
/ 30 ноября 2011

В моем $ dayjob мы используем то, что вы описываете, и то, что я представил на нескольких встречах (см. Слайд 23 и далее). Для этого вам не нужно раскошелиться на Wicket.

По сути, вы копируете код проверки сериализатора и модифицируете его, чтобы включить проверку, а также проверку ошибок сериализации. Затем на последнем этапе цикла запроса вы запускаете собственную программу проверки сериализатора на затронутых страницах.

Проверка, которую мы создали, проверяет наш общий базовый класс, а также сохраняется ли сущность или нет. Если так, мы отклоняем запрос. Кроме того, на нашей базовой странице есть обратный вызов Ajax, который проверяет атрибут сеанса, чтобы определить, не произошла ли ошибка сериализации. Если это так, мы перенаправляем на страницу ошибки с ошибкой сериализации, чтобы разработчики не игнорировали сущность в иерархии страниц.

Вот сущность нашего средства проверки (метод check, переписанный из проверки сериализатора Wicket):

private void check(Object obj)
{
    if (obj == null || obj.getClass().isAnnotationPresent(Deprecated.class)
        || obj.getClass().isAnnotationPresent(SkipClass.class))
    {
        return;
    }

    Class< ? > cls = obj.getClass();
    nameStack.add(simpleName);
    traceStack.add(new TraceSlot(obj, fieldDescription));

    if (!(obj instanceof Serializable) && (!Proxy.isProxyClass(cls)))
    {
        throw new WicketNotSerializableException(toPrettyPrintedStack(obj.getClass().getName())
            .toString(), exception);
    }
    if (obj instanceof IdObject)
    {
        Serializable id = ((IdObject) obj).getIdAsSerializable();
        if (id != null && !(id instanceof Long && ((Long) id) <= 0))
        {
            throw new WicketContainsEntityException(toPrettyPrintedStack(
                obj.getClass().getName()).toString(), exception);
        }
    }
    if (obj instanceof LoadableDetachableModel)
    {
        LoadableDetachableModel< ? > ldm = (LoadableDetachableModel< ? >) obj;
        if (ldm.isAttached())
        {
            throw new WicketContainsAttachedLDMException(toPrettyPrintedStack(
                obj.getClass().getName()).toString(), exception);
        }
    }

Для Wicket 1.5 мы создали наш собственный PageStoreManager, который выполняет эти проверки (и многое другое, например, включение истории просмотра на стороне сервера для наших пользователей). Мы предоставили свой RequestAdapter, переопределив PageStoreManager#newRequestAdapter(IPageManagerContext context) и выполнив проверку сериализации в адаптере:

class DetachCheckingRequestAdapter extends RequestAdapter
{
    public DetachCheckingRequestAdapter(IPageManagerContext context)
    {
        super(context);
    }

    @Override
    protected void storeTouchedPages(List<IManageablePage> touchedPages)
    {
        super.storeTouchedPages(touchedPages);
        if (Application.get().usesDevelopmentConfig())
        {
            for (IManageablePage curPage : touchedPages)
            {
                if (!((Page) curPage).isErrorPage())
                    testDetachedObjects(curPage);
            }
        }
    }

    private void testDetachedObjects(final IManageablePage page)
    {
        try
        {
            NotSerializableException exception = new NotSerializableException();
            EntityAndSerializableChecker checker = new EntityAndSerializableChecker(exception);
            checker.writeObject(page);
        }
        catch (Exception ex)
        {
            log.error("Couldn't test/serialize the Page: " + page + ", error: " + ex);
            Session.get().setDetachException(ex);
        }
    }
}
3 голосов
/ 15 декабря 2012

Более простое решение в Wicket 6.3.0+ см. https://cwiki.apache.org/confluence/display/WICKET/Serialization+Checker

0 голосов
/ 09 декабря 2011

Очень простой подход - настроить сериализацию ваших сущностей:

public Object writeReplace() throws ObjectStreamException {
  if (!isTransient()) {
    throw new NotSerializableException("persistent objects must not be serialized");
  }
  return this;
}

Мы поместили этот фрагмент во все наши объекты (ну, на самом деле, в общий базовый класс с именем AbstractPersistentObject), и он работает довольно хорошо. Единственное, что усложняет, - это редактирование постоянных или временных объектов с постоянными свойствами: вам не разрешено сериализовать грязные / отредактированные / измененные объекты.

...