Verwirrt bzgl. Import-Anweisung bei CDI

Hallo,

ich suche mir nun einen Wolf aber komme nicht weiter.
Ich habe hier eine simple Maven Java WebAnwendung mit Netbeans erstellt.

Ich injiziere mit @Inject eine Java-Klasse:

**import com.mycompany.inject.Greeting;**

import java.io.Serializable;
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.inject.Named;




@Stateless
@Named
public class Printer implements Serializable{

    @Inject
    private Greeting greeting;
    
    public String getGreet(){
        return greeting.greet();
    }

}```

Die Klasse Greeting sieht so aus: 
```@Named
@Stateless
@Default
public class Greeting implements Serializable {

    public Greeting() {
    }

    public String greet() {
        return "Hi";
    }
    
}```

Das funktioniert soweit, aber nur wenn ich in der Klasse Printer die Klasse Greeting importiere. Ist das normal? Ich dachte ein Vorteil ist, dass ich keine Importanweisungen tätigen muss. Die Beispiele im Netz sind leider oft nicht hilfreich. Entweder die import Zeilen sind ausgepunktet oder die Klassen liegen im selben Paket. Kann mir hier jmd, helfen?

Ich gelange letzendlich zu der Überzeugung, dass die imports nötig sind.  :/

Natürlich ist der import nötig, woher soll man sonst wissen welches Greeting?. CDI nimmt dir lediglich ab, dass du selber eine Greeting-Instanz erzeugen und diese im Printer setzen musst.

CDI ermöglicht zum einen einen Scope zu definieren, in dem nach Paketen gesucht wird und zum anderen, können Qualifier erstellt werden, die bei Zweideutigkeit festlegen welche Bean gemeint ist. Ich dachte dadurch, würde die import-Anweisung überflüssig.

Die Injektion geschieht zur Laufzeit durch den Container. Woher sollte zur Compile-Zeit klar sein, welche Klasse gemeint ist?

Was dich verwirren dürfte ist wohl, dass du hier eine konkrete Implementierung vorgibst und injecten lässt. Anders sähe es aus, wenn Greeting ein Interface wäre und du eine zweite Klasse hast, welche das Interface implementiert. Afair (hab bisher nur experimentelle Erfahrung mit JEE/CDI), kümmert sich dann CDI darum, die Implementierung zu injecten.

Aber die import-Anweisung brauchst du immer - da du in der Klasse ja mit der vorgegebenen Objekt arbeiten möchtest.

Kann @Tomate_Salat nur zustimmen. Natürlich ist der Import nötig, die lose Kopplung mit deiner Klasse erhältst du nur, wenn du gegen Interfaces entwickelst. Dann injiziert dir, wenn es von deinem Interface nur eine Implementierung gibt, CDI die richtige Implementierung dazu. Wenn du mehrere Implementierungen verwenden möchtest, musst du zusätzlich noch (z.B. über Annotations) spezifizieren, welche du an dieser Stelle gerne hättest.

Warum diese Verwirrung? Um Markus Struberg zu zitieren: „Wir kochen auch nur mit Wasser.“

Du hast zum einen das Dependency Injection Framework. Das funktioniert haargenau wie bei Google Guice oder Spring auch. In deinem Fall verwendest du - wie es @Tomate_Salat schon erklärt hat - die Implementierung und nicht das Interface. Also hast du auch dieses in den Imports stehen. Wenn dann zur Laufzeit der DI-Container anspringt und die jeweiligen Injection-Points mit Instanzen auffüllt, kommt noch der erste Part des Context Dependency Injection Framework zum Tragen. Die jeweiligen Instanzen werden - je nach Lifecycle-Annotation - instanziert oder wieder verwendet.

Ein beeindruckend geniales Beispiel wie CDI erweitert werden kann ist übrigens InterDyn. Zur Laufzeit einfach mal einen Monitor-Interceptor einhängen weil die Profiler zuviel Performance fressen geht ganz einfach und ohne dass der zu monitorende Code geändert werden muss mit InvoMon.

Welche Implementierung verwendet wird kann man konfigurieren. Früher ging’s ausschließlich mit XML, jetzt gibt’s glaube ich schon Annotations dafür. (Mir persönlich sind die Modulklassen aus Google Guice am liebsten)

Das Eingangsbeispiel wird wohl nur ein Tutorial sein, aber wenn du ohne zusätzliche Abhängigkeiten in der aufrufenden Klasse einen String generieren möchtest (oder auch andere Objekte), dann dürften Producer für dich interessant sein. Damit kannst du Producer für z.B. eine Properties File oder Datenbankverbindungen definieren, und dann an anderer Stelle lediglich eine Instanz injizieren.

http://blog.tim-zoeller.de/producer-mit-cdi/

Danke, das ich da auch ein Interface hinpacken kann, ist mir bewusst, ebenfalls mit Annotation die konkrete Implementierung dann auswählen kann. Aber ich hatte gehofft, dass ich die imports dann sparen kann aber soweit ist die CDI dann doch wohl nicht :slight_smile: Aber dnake für die Rückmeldungen.

Ich frage mich nur, wie weit CDI sein kann damit so etwas funktioniert? Du injizierst die Klasse „Foo“ und rufst die methode „doSomethingAwesome()“ auf, wie soll der Compiler denn ohne Import checken, ob „foo.doSomethingAwesome()“ existiert, und über welchen Rückgabewert die Methode verfügt? So etwas kannst du bei einer statisch typisierten Sprache m.M.n. nicht umsetzen.

Das liegt wie gesagt nicht an CDI - sondern an der Sprache. Wenn du in der Klasse mit einem (hier) Greeting-Objekt arbeiten willst, dann muss das eben bekannt sein. CDI ist eben dann dafür zuständig, dass du das richtige Objekt injected bekommst.

Mal doof gefragt: warum willst du dir den import sparen? Welche Vorteile sollen da hervorgehen? Die IDE kümmert sich doch darum, dass die imports stimmen.

Die “traumhafte” Vorstellung wäre eben das Netz an Beans aufzuspannen durch die Fähigkeiten des Frameworks. Ich beschäftige mich jetzt schon etwas damit und habe auch einige kleinere Komponenten mit CDI, JSF etc. implementiert aber ich habe halt bisher noch nicht den tollen Nutzen von CDI gefühlt. Daher dachte ich jetzt, dass ich da vll. die ganze Zeit etwas falsch verstanden habe und durch Annotation die Verbindung von einzelnen Beans per DI funktionieren.