Spring Scope прокси в режиме AspectJ? - PullRequest
0 голосов
/ 13 июля 2011

Я хочу реализовать некоторые функции для получения текущего пользователя, вошедшего в систему (сущность JPA, представляющая человека, вошедшего в систему).Но вместо того, чтобы делать это классическим способом

CurrentUserService.getCurrentUser(){load the user from db by login}) 

Я хочу сделать это более CDI-способом.

Я хочу иметь CurrentUserFactory, который предоставляет текущему пользователю какbean-объект с областью запроса, доступный с пользовательским квалификатором (текущий bean-компонент).

Qualifier:

@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface CurrentUser {
}

Фабрика:

@Component
public class CurrentUserFactory {

  @CurrentUser
  @Bean
  @Scope(value = WebApplicationContext.SCOPE_REQUEST,
         proxyMode = ScopedProxyMode.TARGET_CLASS)
  public User currentUser() throws IllegalStateException {
      return
          <DoWhatIMean>
             User load form DB by:
             SecurityContextHolder.getContext().getAuthentication().getName()
          </dwim>
}

Использование:

@Controller
@RequestMapping(…)
public AccountController() {

  @Resource
  @CurrentUser
  private User currentUser;

  @RequestMapping(params=”my”)
  public String myAccount () {
     return “redirect:/account/”+currentUser.id;
  }
 }

Это отлично работает.

Но это не удастся (за исключением действительно полезных исключений), если я использую текущего пользователя для прямого JPA (Hibernate), такого как поиск сущности по ссылке на currentUser или сохранение сущности с помощьюссылка на currentUser.- ( Этот сбой понятен. )

Причина в том, что пружина вводит прокси CGI в currentUser.Это работает нормально, пока кто-то использует только свойства этого прокси, но терпит неудачу, если начинает использовать саму ссылку.

Я знаю, что работаю на краю спецификации, и я принимаю, если мойидея не работает.Но я хочу спросить вас, у меня есть идея, чтобы это заработало.Так что разработчик может использовать этот объект currentUser как обычный загруженный JPA объект.

По крайней мере, я хочу, чтобы это было очень простое использование только текущего пользователя:

@Resouce
@CurrenctUser
User currentUser;

и все..

Может, у кого-нибудь есть идея заставить его работать, например, трюк AspectJ (я использую время компиляции AspectJ)?


В любом случае: как я уже говорил, исключения являютсяне моя проблема, я понимаю их, потому что они являются только индикаторами описанной проблемы.

Исключение при попытке загрузки с помощью currentUser (Select b From Bookmark b Where user=?)

java.lang.IllegalStateException: org.hibernate.TransientObjectException: объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом: domain.User

Исключение при попытке сохранить закладку (в закладке есть поле user)

не удалось вставить: [domain.Bookmark];SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)];ограничение [null];вложенное исключение org.hibernate.exception.ConstraintViolationException: не удалось вставить: [domain.Bookmark]

1 Ответ

1 голос
/ 16 июля 2011

Spring-прокси создается ScopedProxyFactoryBean.В документации сказано, что прокси-сервер реализует ScopedObject, который позволяет вам получить доступ к оригинальному компоненту.

@Resource
@CurrentUser
private User currentUser;

public static <T> T unwrapScopedProxy(T maybeProxy) {
    if (maybeProxy instanceof ScopedObject) {
        return (T) ((ScopedObject) maybeProxy).getTargetObject();
    } else {
        return maybeProxy;
    }
}

...
query.setParameter("user", unwrapScopedProxy(currentUser));
...