Spring Component mit Builder

8u3631984

Bekanntes Mitglied
Hallo zusammen ich verwende in meinem Projekt Spring Boot.
Ich habe eine Builder Klasse, die ich mit Autowired verwenden möchte. Dazu habe ich eine @Component Annotation an die Klasse geschrieben.
Hier mein Code (Auszug)
Java:
@Component
@Builder
public class ModelFactory implements IModelFactory {

    private static final Logger logger = LogManager.getLogger(ModelFactory.class);

    private final LocalDateTime dateTime;
    private final String matchNumber;
    private final String team1Name;
    private final String team2Name;
    private final String associationName;
    private final String competitionName;
    private final int seasonStartYear;
    private final int seasonEndYear;
    private final int team1Sets;
    private final int team2Sets;

    @Autowired
    AssociationRepository associationRepository;

    @Autowired
     ClubRepository clubRepository;

    ..

Wenn ich nun in meinem Test die Builder Klasse verwende bekomme ich beim Starten meines Tests folgenden Fehler :
No qualifying bean of type 'java.time.LocalDateTime' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:

Kann mir jemand einen Tipp geben, ob das so überhaupt funktieren kann ?
Vielen Dank für die Unterstützung
[CODE lang="java" title="Testklasse"]@SpringBootTest
class ModelFactoryTest {

@Autowired
ModelFactory modelFactory;
...


[/CODE]

Wenn ich den Test starte bekomme folgenden Fehler :
 
Die ganzen Final Fields in einer per Autowired verwendeten Klasse verwirren mich. Wie sollen die initialisiert werden? Woher soll der Parameterlose Konstruktor die setzen?
 
Danke für deine Anwort. Habe jetzt mal die final Attribute entfernt. Leider bleibt das Problem bestehen.

Ist es denn mit Spring überhaupt möglich einen Builder in einer Component zu haben ?
 
Es sollte natürlich klar sein, dass bei Component, wenn mehrere Threads die verwenden, die ggf. die gleiche Komponente haben. Das heißt, der Zustand ist geteilt über alle.
 
Ich habe nun an meiner Fatory Klasse die @Component Annotation entfernt. Im Test wird der Buildre nun "normal" verwendet.

Allerdings bekomme ich eine Null Pointer Exception wenn ich auf das Repository zugreifen will, was in der Fatory Klasse mit @Autowired anotiert ist
 
Das ist ja auch logisch, weil die Autowired Annotation nur bei Erzeugung durch Spring greifen. Dann musst du das von außen rein reichen.
 
Was der Code dann machen würde ist eine einzelne Instanz von ModelFactory erstellen (und die ist kein Builder!), und zusätzlich hättest du dann eine Klasse ModelFactoryBuilder, mit der du neue Instanzen von ModelFactory erstellen kannst, in denen die Autowired-Felder allerdings null sind – was beides jeweils Unsinn ist.


Einfach mal in's blaue geraten: du hast irgendwie eine Klasse "Model", und brauchst eine Factory, die dir davon Instanzen erzeugt?
 
Das ist ja auch logisch, weil die Autowired Annotation nur bei Erzeugung durch Spring greifen. Dann musst du das von außen rein reichen.
Das is meine TestApplication Klasse :

Java:
@SpringBootApplication
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }
}

[CODE lang="java" title="Meine Fatory Klasse"]
@Builder
public class ModelFactory implements IModelFactory {

private static final Logger logger = LogManager.getLogger(ModelFactory.class);

private LocalDateTime dateTime;
private String matchNumber;
private String team1Name;
private String team2Name;
private String associationName;
private String competitionName;
private int seasonStartYear;
private int seasonEndYear;
private int team1Sets;
private int team2Sets;

@Autowired
AssociationRepository associationRepository;

...[/CODE]


Im test verweden ich dann :
Java:
@SpringBootTest
class ModelFactoryTest {
    
       @Autowired
    AssociationRepository associationRepository;
    ...
    @Test
    public void buildMatch() {
        ModelFactory modelFactory = ModelFactory.builder()
                .associationName(ASSOCIATION_NAME)
                .seasonStartYear(SEASON_START_YEAR)
                .seasonEndYear(SEASON_END_YEAR)
                .competitionName(COMPETITION_NAME)
                .matchNumber(MATCH_NUMBER)
                .dateTime(MATCH_DATE_TIME)
                .team1Name(TEAM1_NAME)
                .team2Name(TEAM2_NAME)
                .team1Sets(RESULT_TEAM1_SETS)
                .team2Sets(RESULT_TEAM2_SETS)
                .build();
 
Irgendwie sieht das Käse aus.

Warum hat eine Factory am Ende so viele Attribute. Was ist die Aufgabe der Klasse ModelFactory, was soll die für Methoden bieten?
 
In Deinem Beispiel ist aber ModelFactory eigentlich das Model und mit der @Builder Annotation erweiterst Du lediglich dieses Model um einen Builder.
 
Die Idee war das in der ModelFactory alle Model Objekte geabut werden sollen und in den Repositories gespeichert werden.
Vielleicht ist das Naming noch nicht so optiomal
 
Die Idee war das in der ModelFactory alle Model Objekte geabut werden sollen und in den Repositories gespeichert werden.
Das entspricht schon etwa einer Factory – nur passt das nicht allzu gut zu deinem Code.

Warum besitzt die Factory zig Felder und warum baut man die Factory mit einem Builder?


BTW: ich würde dir raten auf Lombok zu verzichten. Das sollte man nur nutzen, wenn man die Dinge ohne Lombok sicher umsetzen kann und versteht, was da passiert.
 
Es gibt verschieden Fälle wie man die Objekte bauen kann. Z.B Gibt es Matches mit und ohne ergebnisse. Daher war meine Idee einen Builder um die Factory zu setzen
 
Das kannst Du ja machen, aber die Models bekommen die Builder und die Factory würde dann die Model.builder() nutzen um die Models nach Deinen Kriterien zu bauen.
 
Es gibt verschieden Fälle wie man die Objekte bauen kann. Z.B Gibt es Matches mit und ohne ergebnisse. Daher war meine Idee einen Builder um die Factory zu setzen
Das beantwortet meine Frage nicht. Was soll die Factory tun. Momentan hat die Factory einen Haufen Felder die irgendwelche Werte haben.

Welche Methoden soll die Factory haben? Wie @sascha-sphw schreibt - vermutlich wird die Factory einen ModelBuilder nutzen. Aber der FactoryBuilder liefert genau eine Factory, die kann dann auch nur eine Möglichkeit haben das Model zu bauen auf den ersten Blick.

Bevor du anfängst einen Builder und Co für die Factory zu bauen. Zeig mal die Schnittstelle der Factory. Welche Methoden stellt sie für den Aufrufer mit welchen Parametern zur Verfügung. Das sollte der erste Schritt sein.
 
Java:
public interface IModelFactory {

    /**
     * @return the created {@link IAssociation} object or an empty object
     */
    Optional<IAssociation> buildAssociation();

    /**
     * @return the first created {@link IClub} object or an empty object
     */
    Optional<IClub> buildClub1();

    /**
     * @return the second created {@link IClub} object or an empty object
     */
    Optional<IClub> buildClub2();

    /**
     * @return the created {@link ICompetition} object or an empty object
     */
    Optional<ICompetition> buildCompetition();

    /**
     * @return the created {@link IMatch} object or an empty object
     */
    Optional<IMatch> buildMatch() throws ParameterException;

    /**
     * @return the created {@link IResult} object or an empty object
     */
    Optional<IResult> buildResult() throws ParameterException;

    /**
     * @return the created {@link ISeason} object or an empty object
     */
    Optional<ISeason> buildSeason() throws ParameterException;

    /**
     * @return the first created {@link ITeam} object or an empty object
     */
    Optional<ITeam> buildTeam1() throws ParameterException;

    /**
     * @return the second created {@link ITeam} object or an empty object
     */
    Optional<ITeam> buildTeam2() throws ParameterException;
}
 
Jetzt schau dir mal diese Schnittstelle im Vakuum an. Sieht die sinnvoll aus? Ich verstehe sie nicht. Ich habe eine Klasse, die lauter Methoden ohne Parameter hat. Wenn ich die nutzen soll, kratze ich mich am Kopf, woher die ihre Infos bekommt.
 

Zurück
Oben