2012-06-21 12 views
7

Die JSR-299 Spezifikation Zustände in Abschnitt 3.1:Restricted Generika mit CDI

Wenn die verwaltete Bean-Klasse ein generischer Typ ist, muss es Anwendungsbereich hat @Dependent. Wenn eine verwaltete Bean mit einer parametrisierten Bean-Klasse einen anderen Bereich als @Dependent deklariert, erkennt der Container automatisch das Problem und behandelt es als Definitionsfehler.

Effektiv bedeutet, dass Sie dies nicht tun können:

@Named 
@SessionScoped or @RequestScoped or similar 
public class MyProducer<T> {...} 

Was die technischen Gründe für diese Entscheidung sind?

Wird es in einer kommenden Version von CDI zufällig behoben?

Gibt es eine Best Practice für den Umgang damit?

Danke

EDIT - eine Abhilfe, die ich häufig verwenden kann mit dem benötigten Umfang eine generische POJO-Bohne in eine Bohne zu injizieren. Oft, aber nicht immer.

+0

Große Frage, nebenbei bemerkt.Ich wusste nichts über diese Einschränkung, und es bringt dich wirklich zum Nachdenken. –

Antwort

13

Hier ist eine generische, nicht-abhängige Bean-Klasse:

@ApplicationScoped 
public class FavouriteChooser<T> { 
    public T getFavourite() { 
     // ... 
    } 
} 

Wie viele Instanzen dieser Bohne wird es in der Anwendung sein? Hier

ist eine Injektionsstelle:

@Inject 
private FavouriteChooser<String> favouriteWord; 

Und hier ist eine andere:

@Inject 
private FavouriteChooser<Integer> favouriteNumber; 

Möchten Sie Ihre Antwort ändern? : D

Ooh, und hier ist eine andere:

@Inject 
private FavouriteChooser<CharSequence> favouriteLetters; 

EDIT. Wenn Sie eine Lösung wünschen, würde ich vorschlagen, Ihre generische Klasse abstrakt zu machen und konkrete Unterklassen hinzuzufügen, die den Typ binden. Also:

public abstract class MyProducer<T> {...} 

@Named 
@SessionScoped 
public class MyStringProducer extends MyProducer<String> {} 

@Named 
@SessionScoped 
public class MyIntegerProducer extends MyProducer<Integer> {} 

Es ist boilerplate, aber es ist nur drei Zeilen pro Typ. Denken Sie daran, dass Sie pro Sitzung eine Instanz pro Typ erhalten, die Sie möglicherweise nicht möchten.

+0

Schön - so lange wie Sie die Bean nicht nennen, kann es injiziert werden? Wenn das Scoping beibehalten wird (ist das? - ist jeder FavouriteChooser application-scoped?) Als die einzige Einschränkung wäre, dass ich nicht mit EL-Deklarationen auf sie zugreifen kann? Und widerspricht die Spezifikation nicht? Es sollte schließlich eine gemanagte Bean sein. – kostja

+3

Nein, mein Punkt ist, dass dieser Code nicht funktionieren kann! Ich habe 'FavouriteChooser' als Anwendungsziel definiert, was bedeutet, dass es nur eine Instanz geben kann. Dafür gibt es zwei Injektionsstellen, die mit dem gleichen Objekt * nicht erfüllt werden können. Und das, denke ich, ist der Grund, warum Sie keine Instanzen von generischen Klassen in einem anderen Bereich als dem abhängigen injizieren können. –

+0

Es tut mir leid, dass ich nicht klarer darüber bin, was ich zu sagen versuchte, als ich diese Antwort schrieb. Ich stürzte es einfach ab, ohne Zeit zu haben, es richtig zu erklären:. –

2

Alle nicht abhängigen Scoped Beans müssen proxied werden - AFAIK ist mit generischen Typen nicht möglich.

UPDATE:

Ich würde gerne, dass erklären, genauer zu können, aber ich bin nicht ;-) Weld verwendet javassist, und sie erklären, dass proxying generic types is possible in principle - wenn auch nicht direkt von dem Top-Level-API unterstützt . Aber wir sprechen über die Spezifikation, nicht die Umsetzung von Weld ...

Vielleicht kann jemand anderes die Lücke füllen?

+0

Danke, jan. Es wirft schon ein wenig Licht auf die Sache - es wäre großartig, wenn Sie auch erklären könnten, warum generische Typen nicht proxiiert werden können (ich denke, es hat etwas mit der prinzipiellen Löschung von Java Nemesis zu tun, kann aber nicht darauf hinweisen). – kostja