2011-07-13 6 views
0

現在ログインしているユーザー(現在ログインしているユーザーを表すJPAエンティティ)を取得するための機能を実装したいと考えています。しかし、古典的な方法でそれを行う代わりにSpringスコーププロキシモードAspectJ?

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

私はもっとCDIの方法でそれをやりたいです。

カスタム修飾子(現在のBean)で使用可能な要求スコープ付きBeanとして現在のユーザーを提供するCurrentUserFactoryが必要です。

修飾子:

@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; 
    } 
} 

正常に動作します。

しかし、現在のユーザーをcurrentUserを参照してエンティティを検索したり、currentUserを参照してエンティティを格納したりするような、JPA(Hibernate)の直接的な処理には失敗します。 - (。これが失敗これは明らかである

理由は、バネがあるCurrentUserにおけるCGIプロキシを注入します。これは、このプロキシのプロパティのみを使用している限り正常に動作しますが、参照自体を使用すると失敗します。

私は仕様の辺で作業していることを知っています。私の考えがうまくいかない場合、私は受け入れます。しかし、私はそれを働かせるという考えがあることをあなたに尋ねたいと思う。これにより、開発者は通常のJPA読み込みエンティティのようにこのcurrentUserオブジェクトを使用できます。私が欲しいもの

は、少なくとも現在のユーザのみがこの非常に簡単な使い方です:

@Resouce 
@CurrenctUser 
User currentUser; 

とそれはそれです。

たとえば、AspectJのトリック(私はAspectJのコンパイル時に使用しています)のように、誰かがそれを動作させるアイディアを持っているかもしれませんか?


はとにかく:私が前に言ったように、例外は、彼らが説明した問題の唯一の指標であるので、私はそれらを理解し、私の問題ではありません。私はあるCurrentUser(Select b From Bookmark b Where user=?)によって

java.lang.IllegalStateExceptionをロードしよう

例外:org.hibernate.TransientObjectException:オブジェクトが保存されていない一時的なインスタンスを参照する - フラッシュする前に一時的なインスタンスを保存:domain.User

例外を私がしようとすると、ブックマークを保存する(ブックマークはフィールドユーザーがいる)

挿入しない:[domain.Bookmark]; SQL [insert into bookmark (businessId, reference_Folder_fk, title, user_fk) values (?, ?, ?, ?)];制約[null];ネストされた例外はorg.hibernate.exception.ConstraintViolationExceptionです:挿入できませんでした:[domain.Bookmark]

+0

例外が何であるかを知るのに役立ちます。 –

+0

@matt b:例外を追加しました。 – Ralph

+0

は、それをフェッチする間にどこでも変更されるUserオブジェクトです。 –

答えて

1

春プロキシがScopedProxyFactoryBeanによって作成されます。そのドキュメントでは、プロキシが 'ScopedObject'を実装していて、元のBeanにアクセスできるとしています。

@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)); 
+0

ScopedProxyFactoryBeanとScopedObjectを参照してくれてありがとう。とにかくそれは問題を解決しません。 "私は少なくとも今のユーザーの使い方がとても簡単です..."あなたが提案したのは、クライアントサイドのソリューションです(プログラマーは、そのスタイルを使用して、そのcurrentUserを使用するあらゆる場所で正しい処理をする必要があります)私が必要とするのは、現在のユーザーをどのように使用するかを気にしなくてはならないユーザーのソリューションです。現在のユーザーに提供するプログラマーだけが、この余分なインフラストラクチャの処理を行うことができます。 – Ralph

+1

私はクライアントが@ Resourceがどのように実装されているかを知る必要がないことを基本的に反対しています。それは有効です(そして、あなたが便宜のために建築の純度を妥協することはないと賞賛します)。ジェネリックAPIを作成するとどうなりますか? 'public interface ICurrentUserHolder {ユーザgetCurrentUser(); } 'あなたはプロキシをアンラップする必要があります。インターフェイスの背後にあるアンラップを隠すことができますが、それでもやる必要があります。 –

+0

あなたはクエリをどのように構築するのかは言いませんでしたが、別のオプションは 'setParameter'に渡された任意のSpringプロキシを自動的にアンラップするSpring Queryラッパーを作成することでした。 –

関連する問題