Аннотация Guice @SessionScoped вызывает исключение IllegalArgumentException с Shiro HttpSession

У меня есть приложение Apache Wicket 1.5, которое использует Shiro для обеспечения безопасности и Guice для внедрения зависимостей. Большинство его страниц не имеют состояния, но некоторые объекты моей модели (пользовательские данные, текущее состояние меню и т. д.) должны быть согласованы для всех запросов в одном сеансе. Все эти объекты имеют как логику (в основном простые методы поиска, использующие удаленные интерфейсы EJB3 для доступа к базе данных), так и состояние, и все они реализуют Serializable.

Вот небольшой отрывок, который должен передать идею:

@SessionScoped
public class UsersImpl implements Users, Serializable {

    private static final long serialVersionUID = 8841809043461673585L;
    private final Logger log = LoggerFactory.getLogger( UsersImpl.class );

    @Inject
    public UserService users;

    @Inject
    public RoleService roles;

    private UserDTO currentUser;

    public UserVO findUserByUser( UserVO user ) {
        UserDTO userDto = null;
        try {
            userDto = users.findUserByUser( user.toUserDTO() );
        } catch( Exception e ) {
            log.error( "Error finding user:"+user.id, e );
        }
        return userDto != null ? new UserVO( userDto ) : null;
    }

(...)

}

Я разработал и протестировал классы, используя @Singleton (для простоты), и таким образом все работает нормально, но я часто получаю подобные ошибки, теперь, когда я переключился на @SessionScoped для производства:

Guice provision errors:
1) Error in custom provider, org.apache.shiro.session.InvalidSessionException:
   java.lang.IllegalArgumentException: 
   HttpSession based implementations of the Shiro Session interface requires attribute keys to be String objects.  The HttpSession class does not support anything other than String keys.

Очевидно, что Guice использует какой-то пользовательский объект Key для хранения объектов в сеансе, а реализация Shiro HttpSession не может с этим справиться. Как ни странно, это исключение возникает не для всех классов @SessionScoped, а для более чем одного.

Я искал в Интернете как сумасшедший, ища идею, что я мог бы сделать - какой-то способ заставить Guice использовать строки для ключей, какой-то другой способ сделать HttpSession более совместимым, что угодно - но я не могу найти ничего полезная информация. Кроме того, судя по моим результатам поиска сообщения об ошибке, я, кажется, единственный человек на планете, у которого вообще есть эта проблема...

Есть ли способ заставить это работать? Или я что-то не так здесь делаю?


person weltraumpirat    schedule 26.11.2013    source источник
comment
Как вы инициализируете Shiro? Через установку ShiroModule?   -  person Milan Baran    schedule 26.11.2013
comment
Я установил ShiroAopModule и пользовательский, который расширяет ShiroWebModule и имеет все, что вы в противном случае поместили бы в shiro.ini. Это также связывает SessionScoped.class с ShiroSessionScope. Отдельного модуля для UsersImpl нет - интерфейс Users аннотирован @ImplementedBy.   -  person weltraumpirat    schedule 26.11.2013
comment
Вся настройка работает нормально, если я использую @Singleton вместо @SessionScoped: все инъекции работают, и все приложение работает без ошибок - за исключением того факта, что оно ограничено одним пользователем, конечно.   -  person weltraumpirat    schedule 26.11.2013


Ответы (1)


Что ж, на этот вопрос сложно ответить, но я попытаюсь дать вам несколько вариантов...

Ваша ошибка связана с предварительной проверкой... Итак, я предполагаю, что ваше приложение даже не запустилось, верно? Тогда вы, скорее всего, используете производственную стадию или есть некоторая привязка, созданная с нетерпением, и этот объект ссылается на другой объект в области Session, что является проблемой. Итак, теперь вы должны изменить всю свою прямую инъекцию SessionScope на инъекцию Providers, как в этом примере:

Не могли бы вы изменить

@Inject
public UserService users;

to

@Inject
public Provider<UserService> userProvider; //and call userProvider.get() when you will need it?

Почему так?

  1. SessionScoped объекты доступны только в GuiceFilter.doFilter(), поэтому, если вы смешиваете области действия, это может привести к некоторым исключениям во время выполнения. Особенно, когда вы меняете Stage на Production или устанавливаете для некоторых синглтонов жадную загрузку. Вы можете узнать больше здесь. Рекомендуется использовать Providers при смешивании Scopes.

  2. Проблема может заключаться в том, что Subject привязан только внутри ShiroFilter.doFilter() проверьте мой пост. Затем, если вы находитесь снаружи, скажем, GuiceFilter, в это время не может быть Subject связанного. Снова попробуйте использовать Providers.

Надеюсь, немного поможет.

person Milan Baran    schedule 26.11.2013
comment
Спасибо, попробую провайдеров. Хотя исключение возникает, когда я вызываю страницу - приложение запускается без проблем. - person weltraumpirat; 27.11.2013
comment
После некоторых обширных проб и ударов головой о клавиатуру я думаю, что, возможно, нашел корень всей проблемы: похоже, это было вызвано устаревшей зависимостью (я использую ehcache 2.7.4 для хранения сеансов, и в одном из моих модулей ehcache-core все еще был в гораздо более старой версии). Слишком устал, чтобы тестировать все приложение прямо сейчас, но между прочим: версия без провайдера, кажется, работает нормально, по крайней мере, для того, что я видел с тех пор, как обновил зависимости. Спасибо за помощь, завтра дам точный ответ. - person weltraumpirat; 27.11.2013
comment
Оказывается, исходная ошибка действительно исчезла, теперь, когда я обновил все зависимости до самой последней версии. Однако ваш совет относительно провайдеров а) помог мне встать на правильный путь и б) попутно решил еще одну проблему, с которой я боролся. Поэтому я приму ваш ответ, даже если он не совсем решит вопрос. Еще раз спасибо за помощь! - person weltraumpirat; 27.11.2013