import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import com.editor.helpers.generator;
@Configuration
@PropertySource("classpath:app.properties")
public class Config {
@Value("${generator_name:null}")
String generator_name;
Generator generator = null;
@Bean
@Scope(value="singleton")
public Generator getGenerator() {
if ( generator == null ) {
if ( generator_name == null ) {
throw new IllegalArgumentException();
}
switch ( generator_name.toLowerCase() ) {
case "a" : generator = new GeneratorA();
break;
case "b" : generator = new GeneratorB();
break;
}
}
return generator;
}
}
<beans>
<bean id="generator" class="my.namespace.GeneratorA">
<!-- maybe more options go in here -->
</bean>
</beans>
@Value("${generator_class:null}")
String generatorClass;
Generator generator = null;
@Bean
// @Scope(value="singleton") ==> Singleton ist Standard in Spring, daher ist diese Annotation unnötig.
public Generator getGenerator() {
if (generator == null) {
Class c = Class.forName(generatorClass);
generator = (Generator) c.newInstance();
}
return generator;
}
Ich frage mich gerade nur, wieso Du nicht die GeneratorA und GeneratorB zu Beans machst um dann im Config File halt den Bean entsprechend zu definieren, also sowas wie
Dann hättest Du ein Config File, in dem Du jederzeit einen anderen Generator angeben kannst. Und Du musst keinen Config Bean anpassen ... da gibt es dann keine Abhängigkeit zu den existierenden Generatoren.XML:<beans> <bean id="generator" class="my.namespace.GeneratorA"> <!-- maybe more options go in here --> </bean> </beans>
Oder - so Du unbedingt das in der Art haben willst: Da es ja um eine einmalige Sache geht, könntest Du den kompletten Klassennamen hinterlegen und dann eine neue Instanz erzeugen. Das wäre dann evtl. sowas in der Art (Fehlerbehandlung müsste man noch einfügen):
Java:@Value("${generator_class:null}") String generatorClass; Generator generator = null; @Bean // @Scope(value="singleton") ==> Singleton ist Standard in Spring, daher ist diese Annotation unnötig. public Generator getGenerator() { if (generator == null) { Class c = Class.forName(generatorClass); generator = (Generator) c.newInstance(); } return generator; }
Bei beiden Varianten hast Du keine Abhängigkeit von einer Klasse zu allen bekannten Generator Implementationen.
Und die Exception wirst du bei Dir und bei meiner letzteren Methode dann nur da abfangen können, wo getGenerator aufgerufen wird.
Bei der ersten Version von mir würde beim Start der Applikation der Bean nicht erzeugt werden können (sowie alle davon abhängigen Beans). Da muss man also beim App Server entsprechend ein Monitoring haben (oder eben bei Updates immer verifizieren
Class c = Class.forName(generatorClass);
generator = (Generator) c.newInstance();
Ich habe mir https://www.baeldung.com/spring-profiles. Diese bezieht sich allerdings darauf wann eine Bean verwendet werden soll. Deshalb verstehe ich gerad nicht so recht, wie du von meinem Problem hierauf kommst????Würde ich auch nicht so machen.
Ich denke für dich würde es sich anbieten via Spring Profiles die richtigen Beans zu laden. Mit newInstance sind sie mMn auch nicht sauber im Spring Context.
Siehe: https://www.baeldung.com/spring-profiles
/e xml configs würde ich in aktuellem Versionen auch nicht mehr unbedingt verwenden
Im Augenblick soll es erstmal eine einmalige Konfiguration sein, aber ich könnte mir später auch Vorstellen, dass die Eingabe gewechselt wird.Die Frage ist doch: kannst du da sinnvoll etwas machen? Wenn du Generator A und B hast und jemand gibt C an?
Ist das eine Art Eingabe die ständig kommt oder ist das einmalige Konfiguration?
Einmalige Konfiguration solltest du beim Start dem Admin um die Ohren hauen ... so wie es bei der Definition als Bean direkt passiert. Das ist halt etwas, das ordentlich und sorgfältig gemacht werden muss ...
Lass in jedem Fall den Check auf null weg. Das ist nicht Thread-Sicher, und wird sowieso von Spring behandelt.Oder wie würdet ihr es realisieren?
Gar nicht - wenn der Entwickler die Anwendung nicht korrekt konfiguriert, muss die nicht starten, sondern kann ruhig mit Exception beendet werden.Und wo sollte ich die InvalidArgumentException abfangen bzw. bearbeiten?
public Generator getGenerator
bekommen, dann ist kein switch oä mehr nötig.[USER=22881]@Bean[/USER]
den jeweiligen Generator verfügbar macht.@ConditionalOnMissingBean
annotieren, damit man die Bean einfach überschrieben kann.@ConfigurationProperties("...")
public class GeneratorProperties {
Type generator;
public enum Type {
A {
Generator getGenerator() {
return ...;
}
}, B {
@Override
Generator getGenerator() {
return ...
}
};
abstract Generator getGenerator();
}
}
public class GeneratorProvider {
@Autowired
GeneratorProperties generatorProperties;
@Bean
@ConditionalOnMissingBean(Generator.class)
public Generator generator() {
return generatorProperties.type.getGenerator();
}
}
Wie sollte man am besten die ClassNotFoundException behandeln für
wenn z.B. eine nicht existende Klasse angibt?Code:Class c = Class.forName(generatorClass);
Ich kann aus deinem Beispiel nicht erkennen, an welcher Stelle aus der Datei "app.properties" der Wert gelesen wird und anhand dessen entschieden wird welcher Generator benutzt werden soll.Erstmal zu deinem Code:
Lass in jedem Fall den Check auf null weg. Das ist nicht Thread-Sicher, und wird sowieso von Spring behandelt.
Gar nicht - wenn der Entwickler die Anwendung nicht korrekt konfiguriert, muss die nicht starten, sondern kann ruhig mit Exception beendet werden.
Die Exception sollte aber sinnvoller gewählt werden, mindestens mit einer vernünftigen Message, tendenziell aber auch mit anderem Typ (da ja an der Stelle kein Argument übergeben wird).
Dann wie man es anders lösen könnte:
Generell Type-safe Configuration Properties dafür nutzen.
Statt magischen Strings einen Enum dafür nutzen.
Der enum kann dann auch einfach einepublic Generator getGenerator
bekommen, dann ist kein switch oä mehr nötig.
Ein von der Properties-Klasse getrennter Provider, der die Properties-Klasse injiziert bekommt, und über[USER=22881]@Bean[/USER]
den jeweiligen Generator verfügbar macht.
Den Provider mit@ConditionalOnMissingBean
annotieren, damit man die Bean einfach überschrieben kann.
Grob so: (vermutlich voller Fehler, aber als Idee sollte das reichen)
Java:@ConfigurationProperties("...") public class GeneratorProperties { Type generator; public enum Type { A { Generator getGenerator() { return ...; } }, B { @Override Generator getGenerator() { return ... } }; abstract Generator getGenerator(); } }
Java:public class GeneratorProvider { @Autowired GeneratorProperties generatorProperties; @Bean @ConditionalOnMissingBean(Generator.class) public Generator generator() { return generatorProperties.type.getGenerator(); } }
Ich kann aus deinem Beispiel nicht erkennen, an welcher Stelle aus der Datei "app.properties" der Wert gelesen wird und anhand dessen entschieden wird welcher Generator benutzt werden soll.
@ConfigurationProperties
und dem Attribut-Namen wird der Key in der properties Datei gebildet, Der Wert des Attributes ist dann der dort eingetragene Wert.generator()
wird einfach nur die getGenerator-Methode des Enums aufgerufen, der gibt dann den Generator zurück. (alle "..." müssen dafür natürlich noch sinnvoll gefühlt werden)Ok, also ich arbeite an einem Editor, dieser verwendet verschiedene Generatoren, abhängig von der Konfiguration. Aus den jeweiligen Generatoren erhalte ich bestimmte feste Werte und Funktionen. Diese Funktionen verwendet gleiche Funktionen, die allerdings unterschiedliches zurückliefern.Test, dev, prod sind ja nur Beispiele. das könnte auch hund, katze oder huhn sein...
Aber mit dem Vorschlag von @mrBrown solltest du ja jetzt genug Ideen und Ansätze haben um es so umzusetzen wie du willst.
Sonst musst du den Use-Case noch genauer vorstellen.
Würde ich im Spring (oder EE) Kontext aber beides nicht benutzen, dabei sollte man die immer vom jeweiligen Framework erzeugen lassen, damit man zB andere Beans injiziert bekommt.Also erst einmal zu dem newInstance - das ist tatsächlich ab Java9 deprecated (zeigt, wie lange ich das nicht genutzt habe.... man nutzt in der Regel andere Lösungen) - aber das ist doch trivial zu lösen und Google liefert da schnell den neuen weg:
Und mittels getConstructor().newInstance() fuktioniert es dann ab Java 9.
Die Idee von @mrBrown ist die Lösung / Idee, die sehr schön ist, wenn man eine klare, feste Menge an Elementen hat. Aber es muss halt diese feste Menge an Elementen geben.
[USER=22881]@Bean[/USER] Generator generator() { return new MeinNeuerGenerator();}
und das bestehende wird überschrieben.Würde ich im Spring (oder EE) Kontext aber beides nicht benutzen, dabei sollte man die immer vom jeweiligen Framework erzeugen lassen, damit man zB andere Beans injiziert bekommt.
Ja stimmt, daran habe ich nicht gedacht. Aber klar: Wenn einem die Möglichkeiten der "mitgelieferten" Generatoren nicht zusagt, dann könnte man natürlich diesen ganzen Bean austauschen um dann den eigenen Generator so einzubringen.Jein, nur die feste Menge an Elementen kann man über die Konfiguration angeben. Wenn man eine andere Generator-Klasse nutzen will, klappt das einfach über eine eigene[USER=22881]@Bean[/USER] Generator generator() { return new MeinNeuerGenerator();}
und das bestehende wird überschrieben.
Das newInstance könnte man mit BeanFactory#getBean ersetzen, dann hätte man weiterhin die Flexibilität mit dem Klassennamen, aber es wird trotzdem über Spring initialisiertDa bin ich auf jeden Fall ganz Deiner Meinung. Ich finde die Lösung, das über eine Spring Konfiguration zu lösen, auch deutlich besser. Aber nach dem Hinweis bzgl. des Deprecated wollte ich den Weg zumindest kurz ohne deprecated Methoden skizzieren.
Die Frage ist, ob man dies als Bean haben möchte. Diese Alternative habe ich ja eigentlich nur gebracht, falls er da aus irgendwelchen Gründen da eben diese Klassen nicht als Beans handhaben möchte (Und da braucht es keinen Bean, der mir dann einen Bean aus einer Konfigurationsdatei gibt.... Das hat man doch alles so man es haben möchte...).Das newInstance könnte man mit BeanFactory#getBean ersetzen, dann hätte man weiterhin die Flexibilität mit dem Klassennamen, aber es wird trotzdem über Spring initialisiert
Gehe ich recht in der Annahme, dass Type vonErstmal zu deinem Code:
Lass in jedem Fall den Check auf null weg. Das ist nicht Thread-Sicher, und wird sowieso von Spring behandelt.
Gar nicht - wenn der Entwickler die Anwendung nicht korrekt konfiguriert, muss die nicht starten, sondern kann ruhig mit Exception beendet werden.
Die Exception sollte aber sinnvoller gewählt werden, mindestens mit einer vernünftigen Message, tendenziell aber auch mit anderem Typ (da ja an der Stelle kein Argument übergeben wird).
Dann wie man es anders lösen könnte:
Generell Type-safe Configuration Properties dafür nutzen.
Statt magischen Strings einen Enum dafür nutzen.
Der enum kann dann auch einfach einepublic Generator getGenerator
bekommen, dann ist kein switch oä mehr nötig.
Ein von der Properties-Klasse getrennter Provider, der die Properties-Klasse injiziert bekommt, und über[USER=22881]@Bean[/USER]
den jeweiligen Generator verfügbar macht.
Den Provider mit@ConditionalOnMissingBean
annotieren, damit man die Bean einfach überschrieben kann.
Grob so: (vermutlich voller Fehler, aber als Idee sollte das reichen)
Java:@ConfigurationProperties("...") public class GeneratorProperties { Type generator; public enum Type { A { Generator getGenerator() { return ...; } }, B { @Override Generator getGenerator() { return ... } }; abstract Generator getGenerator(); } }
Java:public class GeneratorProvider { @Autowired GeneratorProperties generatorProperties; @Bean @ConditionalOnMissingBean(Generator.class) public Generator generator() { return generatorProperties.type.getGenerator(); } }
import java.lang.reflect.Type;
Ne, Type ist doch dort deklariert:Gehe ich recht in der Annahme, dass Type von
ist?Code:import java.lang.reflect.Type;
public enum Type {
A ...
@Configuration
class AnnotationConfig {
@Bean(name = {"tiger", "kitty"})
@Scope(value = "prototype")
Tiger getTiger(String name) {
return new Tiger(name);
}
@Bean(name = "lion")
Lion getLion() {
return new Lion("Hardcoded lion name");
}
interface Animal {}
}
Ups! Ahh stimmt. Du hast Recht.Ne, Type ist doch dort deklariert:public enum Type { A ...
Ups, übersehen, dass die Funktion ja gleich heissen mussIch habe mir mal die Seite https://www.baeldung.com/spring-getbean durchgelesen.
Das Beispiel:
Code:@Configuration class AnnotationConfig { @Bean(name = {"tiger", "kitty"}) @Scope(value = "prototype") Tiger getTiger(String name) { return new Tiger(name); } @Bean(name = "lion") Lion getLion() { return new Lion("Hardcoded lion name"); } interface Animal {} }
scheint das Abzubilden, was ich versuche zu realisieren, allerdings wie bekomme ich aus meiner app.properties die Werte, in diesem Falle "tiger", "lion" und Co. übermittelt. Dazu fehlt mir noch etwas das Grundverständnis.
Ne, muss sie nicht - ist allerdings was völlig anderes, als die anderen Varianten:Ups, übersehen, dass die Funktion ja gleich heissen muss
Ich habe mir mal die Seite https://www.baeldung.com/spring-getbean durchgelesen.
Das Beispiel [...] scheint das Abzubilden, was ich versuche zu realisieren, allerdings wie bekomme ich aus meiner app.properties die Werte, in diesem Falle "tiger", "lion" und Co. übermittelt. Dazu fehlt mir noch etwas das Grundverständnis.
@ConfigurationProperties("...")
public class GeneratorProperties {
Type generator;
public enum Type {
A {
Generator getGenerator() {
return ...;
}
}, B {
@Override
Generator getGenerator() {
return ...
}
};
abstract Generator getGenerator();
}
}
public class GeneratorProvider {
@Autowired
GeneratorProperties generatorProperties;
@Bean
@ConditionalOnMissingBean(Generator.class)
public Generator generator() {
return generatorProperties.type.getGenerator();
}
}
package com.editor.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
@Configuration
@PropertySource("classpath:app.properties")
public class GeneratorProperties {
Type generator;
public enum Type {
GeneratorA {
Generator getGenerator() {
return new GeneratorA();
}
};
abstract Generator getGenerator();
}
}
package com.editor.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
public class GeneratorProvider {
@Autowired
GeneratorProperties generatorProperties;
@Bean
@ConditionalOnMissingBean(GeneratorA.class)
public Generator generator() {
return generatorProperties.generator.getGenerator();
}
}
package com.editor.helpers.generator;
public abstract class Generator {
public static String getString( String base_directory ) {
return null;
}
public static State getIState() {
return null;
}
}
package com.editor.helpers.generator;
public abstract class Generator {
public static String getName() {
return null;
}
}
package com.editor.helpers.generator;
public class GeneratorA extends Generator {
public static String getName() {
return "GeneratorA";
}
}
generator = generatora
package com.editor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties
public class EditorApplication {
public static void main(String[] args) {
SpringApplication.run(EditorApplication.class, args);
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.2.RELEASE)
2020-01-15 05:05:02.319 INFO 9956 --- [ restartedMain] com.editor.BuilderApplication : Starting BuilderApplication on Tommys-Rechner with PID 9956 (C:\Projekte\java\git\Builder\Builder\target\classes started by tomth in C:\Projekte\java\git\Builder\Builder)
2020-01-15 05:05:02.321 INFO 9956 --- [ restartedMain] com.editor.BuilderApplication : No active profile set, falling back to default profiles: default
2020-01-15 05:05:02.356 INFO 9956 --- [ restartedMain] o.s.b.devtools.restart.ChangeableUrls : The Class-Path manifest attribute in C:\Users\tomth\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.2\jaxb-runtime-2.3.2.jar referenced one or more files that do not exist: file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.xml.bind-api-2.3.2.jar,file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/txw2-2.3.2.jar,file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/istack-commons-runtime-3.0.8.jar,file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/stax-ex-1.8.1.jar,file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/FastInfoset-1.2.16.jar,file:/C:/Users/tomth/.m2/repository/org/glassfish/jaxb/jaxb-runtime/2.3.2/jakarta.activation-api-1.2.1.jar
2020-01-15 05:05:02.357 INFO 9956 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-01-15 05:05:02.357 INFO 9956 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2020-01-15 05:05:02.781 INFO 9956 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2020-01-15 05:05:02.828 INFO 9956 --- [ restartedMain] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 41ms. Found 2 JPA repository interfaces.
2020-01-15 05:05:03.041 INFO 9956 --- [ restartedMain] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2020-01-15 05:05:03.257 INFO 9956 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-01-15 05:05:03.263 INFO 9956 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-01-15 05:05:03.263 INFO 9956 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.29]
2020-01-15 05:05:03.376 INFO 9956 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-01-15 05:05:03.376 INFO 9956 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 1019 ms
2020-01-15 05:05:03.486 INFO 9956 --- [ restartedMain] o.hibernate.jpa.internal.util.LogHelper : HHH000204: Processing PersistenceUnitInfo [name: default]
2020-01-15 05:05:03.546 INFO 9956 --- [ restartedMain] org.hibernate.Version : HHH000412: Hibernate Core {5.4.9.Final}
2020-01-15 05:05:03.638 INFO 9956 --- [ restartedMain] o.hibernate.annotations.common.Version : HCANN000001: Hibernate Commons Annotations {5.1.0.Final}
2020-01-15 05:05:03.710 INFO 9956 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2020-01-15 05:05:03.809 INFO 9956 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2020-01-15 05:05:03.817 INFO 9956 --- [ restartedMain] org.hibernate.dialect.Dialect : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
Hibernate: drop table if exists languages
Hibernate: drop table if exists user
Hibernate: create table languages (id bigint not null auto_increment, created_at datetime, iso varchar(255) not null, name varchar(255) not null, updated_at datetime, created_by bigint, updated_by bigint, primary key (id)) engine=MyISAM
Hibernate: create table user (id bigint not null auto_increment, created_at datetime, email varchar(255), firstname varchar(255), lastname varchar(255), password varchar(255), updated_at datetime, created_by bigint, updated_by bigint, primary key (id)) engine=MyISAM
Hibernate: alter table languages add constraint FK6pb75mfcy4xyf5olu4j0abcoi foreign key (created_by) references user (id)
Hibernate: alter table languages add constraint FKn3mumfixnk1277loo0yy5lc4l foreign key (updated_by) references user (id)
Hibernate: alter table user add constraint FKdltbr5t0nljpuuo4isxgslt82 foreign key (created_by) references user (id)
Hibernate: alter table user add constraint FK2a54xhceitopkkw1hlo3tkv3i foreign key (updated_by) references user (id)
2020-01-15 05:05:04.389 INFO 9956 --- [ restartedMain] o.h.e.t.j.p.i.JtaPlatformInitiator : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-01-15 05:05:04.394 INFO 9956 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-01-15 05:05:04.417 INFO 9956 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2020-01-15 05:05:04.471 WARN 9956 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'localizationService': Unsatisfied dependency expressed through field 'generator'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.editor.helpers.generator.Generator' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
2020-01-15 05:05:04.471 INFO 9956 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
2020-01-15 05:05:04.474 INFO 9956 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2020-01-15 05:05:04.542 INFO 9956 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
2020-01-15 05:05:04.544 INFO 9956 --- [ restartedMain] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2020-01-15 05:05:04.551 INFO 9956 --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-01-15 05:05:04.635 ERROR 9956 --- [ restartedMain] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field generator in com.editor.service.LocalizationService required a bean of type 'com.editor.helpers.generator.Generator' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.editor.helpers.generator.Generator' in your configuration.
präfix.generator = xyz
an. Das ganze muss dann noch explizit aktiviert werden mit EnableConfigurationProperties an deiner Haupt-Klassesrc/main/resource
ist vermutlich nur ein Tippfehler?package com.editor.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
@ConfigurationProperties(prefix = "generator")
@PropertySource("classpath:app.properties")
public class GeneratorProperties {
Type type;
public enum Type {
GeneratorA {
Generator getGenerator() {
return new GeneratorA();
}
};
abstract Generator getGenerator();
}
}
package com.editor.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
@Configuration
public class GeneratorProvider {
@Autowired
GeneratorProperties generatorProperties;
@Bean
@ConditionalOnMissingBean(GeneratorA.class)
public Generator generator() {
return generatorProperties.generator.getGenerator();
}
}
package com.editor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties
public class EditorApplication {
public static void main(String[] args) {
SpringApplication.run(EditorApplication.class, args);
}
}
framework.type = GENERATORA
package com.editor.helpers.generator;
public interface Generator {
String getName( );
}
package com.editor.helpers.generator;
public class GeneratorA implements Generator {
public String getName() {
return "GeneratorA";
}
}
Ist hierbei die Groß-/Kleinschreibung zu beachten? Wenn ja, wie könnte ich es erreichen, dass die Groß-/Kleinschreibung egal wäre?
- xyz muss nicht irgendein beliebiger String sein, sondern dem Enum entsprechen. Wenn du den Enum 'A' nennst, sollte es auch A sein, nicht "generatora"
Stimmt. Darüber hatte ich noch gar nicht nachgedacht. Verwende keine statischen Funktionen mehr in den Klassen.Ist dir generell bewusst, was für eine Auswirkung die statischen Methoden in Generator und den Subklassen haben?
***************************
APPLICATION FAILED TO START
***************************
Description:
Field generator in com.editor.service.LocalizationService required a bean of type 'com.editor.helpers.generator.Generator' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.editor.helpers.generator.Generator' in your configuration.
@ConfigurationPropertiesScan
angebenIst hierbei die Groß-/Kleinschreibung zu beachten? Wenn ja, wie könnte ich es erreichen, dass die Groß-/Kleinschreibung egal wäre?
Nicht beim Kompilieren, beim Ausführen.Beim Compilieren erhalte ich immer noch die Ausgabe
generator.type = GENERATORA
package com.editor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties
@ConfigurationPropertiesScan
public class EditorApplication {
public static void main(String[] args) {
SpringApplication.run(EditorApplication.class, args);
}
}
package com.editor.helpers.generator;
public interface Generator {
String getName( );
}
package com.editor.helpers.generator;
public class GeneratorA implements Generator {
public String getName() {
return "GeneratorA";
}
}
package com.editor.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
@ConfigurationProperties(prefix = "generator")
public class GeneratorProperties {
Type type;
public enum Type {
GeneratorA {
Generator getGenerator() {
return new GeneratorA();
}
};
abstract Generator getGenerator();
}
}
package com.editor.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.editor.helpers.generator.Generator;
import com.editor.helpers.generator.GeneratorA;
@Configuration
public class GeneratorProvider {
@Autowired
GeneratorProperties generatorProperties;
@Bean
@ConditionalOnMissingBean(GeneratorA.class)
public Generator generator() {
return generatorProperties.type.getGenerator();
}
}
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.2.RELEASE)
2020-01-15 19:33:44.846 INFO 25756 --- [ restartedMain] com.editor.EditorApplication : Starting EditorApplication on Tommys-Rechner with PID 25756 (C:\Projekte\java\Editor\target\classes started by tomth in C:\Projekte\java\Editor)
2020-01-15 19:33:44.847 INFO 25756 --- [ restartedMain] com.editor.EditorApplication : No active profile set, falling back to default profiles: default
2020-01-15 19:33:44.875 INFO 25756 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2020-01-15 19:33:45.136 WARN 25756 --- [ restartedMain] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generator' defined in class path resource [com/editor/config/GeneratorProvider.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.editor.helpers.generator.Generator]: Factory method 'generator' threw exception; nested exception is java.lang.NullPointerException
2020-01-15 19:33:45.141 INFO 25756 --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-01-15 19:33:45.149 ERROR 25756 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generator' defined in class path resource [com/editor/config/GeneratorProvider.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.editor.helpers.generator.Generator]: Factory method 'generator' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:656) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:484) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1338) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at com.editor.EditorApplication.main(EditorApplication.java:14) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.2.2.RELEASE.jar:2.2.2.RELEASE]
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.editor.helpers.generator.Generator]: Factory method 'generator' threw exception; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
... 23 common frames omitted
Caused by: java.lang.NullPointerException: null
at com.editor.config.GeneratorProvider.generator(GeneratorProvider.java:19) ~[classes/:na]
at com.editor.config.GeneratorProvider$$EnhancerBySpringCGLIB$$ae9b9c5f.CGLIB$generator$0(<generated>) ~[classes/:na]
at com.editor.config.GeneratorProvider$$EnhancerBySpringCGLIB$$ae9b9c5f$$FastClassBySpringCGLIB$$4391d635.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at com.editor.config.GeneratorProvider$$EnhancerBySpringCGLIB$$ae9b9c5f.generator(<generated>) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:567) ~[na:na]
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
... 24 common frames omitted
Wie ein Array daraus? Verstehe die NotationMach das FeldType type[/type] mal private und ergänz Getter und Setter (hätte ich explizit sagen sollen...)
Type type[/type]
package com.editor.services;
import org.springframework.beans.factory.annotation.Autowired;
import com.editor.helpers.generator.Generator;
public class GeneratorService {
@Autowired
Generator generator;
public String getName() {
return generator.getName();
}
}
package com.editor.services;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class GeneratorServiceTest {
@Autowired
GeneratorService generatorService;
@Test
void testGetName() {
String generator = "GeneratorA";
assertTrue(generatorService.getName().equals( generator ));
}
}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.editor.services.GeneratorServiceTest': Unsatisfied dependency expressed through field 'generatorService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.editor.services.GeneratorService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:393)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734)
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:336)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:259)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:252)
at java.base/java.util.Optional.orElseGet(Optional.java:369)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:251)
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.editor.services.GeneratorService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
... 69 more
Weis jemand was hier gerade schief läuft?...
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.editor.services.GeneratorServiceTest': Unsatisfied dependency expressed through field 'generatorService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.editor.services.GeneratorService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:116) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1422) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireBeanProperties(AbstractAutowireCapableBeanFactory.java:393) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:119) ~[spring-test-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83) ~[spring-test-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:43) ~[spring-boot-test-autoconfigure-2.2.2.RELEASE.jar:2.2.2.RELEASE]
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244) ~[spring-test-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98) ~[spring-test-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195) ~[na:na]
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177) ~[na:na]
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484) ~[na:na]
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) ~[na:na]
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) ~[na:na]
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) ~[na:na]
at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) ~[na:na]
at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) ~[na:na]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.invokeTestInstancePostProcessors(ClassBasedTestDescriptor.java:336) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.instantiateAndPostProcessTestInstance(ClassBasedTestDescriptor.java:259) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$2(ClassBasedTestDescriptor.java:252) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at java.base/java.util.Optional.orElseGet(Optional.java:369) ~[na:na]
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$testInstancesProvider$3(ClassBasedTestDescriptor.java:251) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.execution.TestInstancesProvider.getTestInstances(TestInstancesProvider.java:29) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$prepare$0(TestMethodTestDescriptor.java:106) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:105) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.prepare(TestMethodTestDescriptor.java:69) ~[junit-jupiter-engine-5.5.2.jar:5.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$prepare$1(NodeTestTask.java:107) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.prepare(NodeTestTask.java:107) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:75) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at java.base/java.util.ArrayList.forEach(ArrayList.java:1540) ~[na:na]
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51) ~[junit-platform-engine-1.5.2.jar:1.5.2]
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229) ~[.cp/:na]
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197) ~[.cp/:na]
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211) ~[.cp/:na]
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191) ~[.cp/:na]
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137) ~[.cp/:na]
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89) ~[.cp/:na]
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41) ~[.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541) ~[.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763) ~[.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463) ~[.cp/:na]
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209) ~[.cp/:na]
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.editor.services.GeneratorService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1695) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1253) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1207) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.2.2.RELEASE.jar:5.2.2.RELEASE]
... 69 common frames omitted
Kenne mich mit Spring nicht aus, aber muss die GeneratorService-Klasse nicht annotiert werden, z. B. mitWeis jemand was hier gerade schief läuft?
@Service
oder @Component
?