#ConfigurationProperties does not work when using classes in the #SpringBootTest - java

application.yml
foo:
name: hun
FooConfigurationProperty
foo.name in application.yml is bound.
#Getter
#Setter
#Component
#ConfigurationProperties("foo")
public class FooConfigurationProperty {
private String name;
}
For quick testing, the FooConfigurationProperty bean was added using the classes property.
FooTest
#SpringBootTest(classes = FooConfigurationProperty.class)
public class FooTest {
#Autowired
FooConfigurationProperty fooConfigurationProperty;
#Test
public void fooTest() {
System.out.println(fooConfigurationProperty.getName());
}
}
The above results are output null rather than hun.
Why is null output when classes have specified to use a specific bean?

Related

NoUniqueBeanDefinitionException: No qualifying bean of type 'AppProperties' available: expected single matching bean but found 3

I am trying to load the api key value from the application.properties file and below are the class files. I am unable to start the application as it is not able to find the unique bean. Not sure what i am missing. Can someone please help.
This is our AppProperties.java
#Component
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix = AppProperties.APP_PROPERTIES_PREFIX)
public class AppProperties {
public static final String APP_PROPERTIES_PREFIX = "bi";
private String accessTokenUri;
private String clientId;
private String clientSecret;
private String basicAuth;
private String apiKey;
//getters and setters
}
This is our DiagnosticProperties.java
#Component
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix = "bi")
public class DiagnosticProperties extends AppProperties {
private String diagnosisUrl;
//getters and setters
}
This is our ObservationProperties.java
#Component
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix = "bi")
public class ObservationProperties extends AppProperties {
private String observationUrl;
//getters and setters
}
This is our DiagnosticServiceImpl.java
#Service
public class DiagnosticServiceImpl implements DiagnosticService {
private static final Logger LOGGER =
LoggerFactory.getLogger(ObservationServiceImpl.class);
private final WebClient webClient;
private final DiagnosticProperties diagnosticProperties;
public DiagnosticServiceImpl(final WebClient webClient,final DiagnosticProperties
diagnosticProperties) {
this.webClient = webClient;
this.diagnosticProperties = diagnosticProperties;
}
#Override
public Mono<DiagnosticResponse> getPatientDiagnosticDetails(final String uri) {
return diagnosticDetails(uri);
}
You should not put any annotations on the AppProperties (that could have been an abstract class). The classes that inherit from it only need #ConfigurationProperties(prefix = "..") and #Component or they could be also enabled with #EnableConfigurationProperties from another configuration class.
When you inject - be specific about which configuration properties you want to inject - either by specifying a type - like you did in your example, or by adding #Qualifier("bean-name") to the parameter on the injection point.
Spring Boot out-of-the-box configures application.properties property source.

Spring: Can't override properties with #ConfigurationProperties for test

I'm trying to configure property for test, using #ConfigurationProperties.
My config-class with properties:
#Data
#Configuration
#ConfigurationProperties(prefix = "data")
public class TestFileSettings {
private String dockerMountPath;
}
Property-file "application-test.properties" contains:
data.docker_mount_path=testMountHostDirectory/
And test-class:
#ActiveProfiles("test")
#TestPropertySource(locations = "classpath:application-test.properties")
#EnableConfigurationProperties(value = {TestFileSettings.class})
#RunWith(SpringRunner.class)
#SpringBootTest()
public class PropertyAcessTest {
#Autowired
private TestFileSettings testFileSettings;
#Test()
public void testPropertyAcess() {
String getDockerMountPath = testFileSettings.getDockerMountPath();
assertEquals("testMountHostDirectory/", getDockerMountPath)
{
But I get the following error:
error: cannot find symbol
String getDockerMountPath = testFileSettings.getDockerMountPath();
^
symbol: method getDockerMountPath()
location: variable testFileSettings of type TestFileSettings
What am I doing wrong?

ConfigurationProperties for final fields doesn't work

I need to set data from application.yml file to my config class but when I trying to do it I get an error:
TestConfig is annotated with #ConstructorBinding but it is defined as a regular bean which caused dependency injection to fail.
My application.yml file looks like the following:
test:
app:
id: app_id
My TestConfig class looks like this:
#Configuration
#ConfigurationProperties(prefix = "test.app")
#ConstructorBinding
public class TestConfig {
private final String id;
public TestConfig(String id) {
this.id = id;
}
}
I'm trying to do like this but it doesn't work for me.
Where I was wrong?
According to :
https://www.baeldung.com/configuration-properties-in-spring-boot#immutable-configurationproperties-binding
You will need to remove the #Configuration from your TestConfig.class.
Furthermore, it's important to emphasize that to use the constructor binding, we need to explicitly enable our configuration class either with #EnableConfigurationProperties or with #ConfigurationPropertiesScan.
--------- Edited -----
#ConfigurationProperties(prefix = "test.app")
#ConstructorBinding
public class TestConfig {
private final int id;
public TestConfig (int id)
this.id = id
}
public String getId() {
return id;
}
}
#SpringBootApplication
#ConfigurationPropertiesScan
public class YourApp{
public static void main(String[] args) {
SpringApplication.run(YourApp.class, args);
}
}

Spring Boot Autowiring From Another Module

I am trying to establish connection between 3 modules in my project. When I try to reach my object with #Autowired error shows up. I'll explain my scenario a little bit.
MODULES
All of these modules have been connected inside of pom.xml. Lets talk about my problem.
C -> ROUTE.JAVA
.
.
.
#Autowired
public CommuniticationRepository;
#Autowired
public Core core;
.
.
.
B -> CORE
public class Core {
private int id;
private String name;
private Date date;
public Core(int id, String name, Date date) {
this.id = id;
this.name = name;
this.date = date;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
}
ERROR
Field communicationRepositoryin com.demo.xyz.A.RestControllers.Route required
a bean of type 'com.demo.xyz.A.CommunicationRepository' that could not be
found.
Action:
Consider defining a bean of type 'com.demo.xyz.A.CommunicationRepository' in
your configuration.
A - > REPOSITORY.JAVA
#Component
#Repository
public interface CommunicationRepository extends CrudRepository<Communication, Date> {
List<Communication> findByDate(Date date);
void countByDate(Date date);
}
You should remove #Component and #Repository from CommunicationRepository if it is a spring data JPA repository.
You should define configurations in modules A and B.
#Configuration
#EnableJpaRepositories(basePackages ={"com.demo.xyz.A"})
#EntityScan(basePackages = {"com.demo.xyz.A"})
#ComponentScan(basePackages = {"com.demo.xyz.A"})
public class ConfigA {
}
// If you have no spring managed beans in B this is not needed
// If Core should be a spring managed bean, add #Component on top of it
#Configuration
#ComponentScan(basePackages = {"com.demo.xyz.B"})
public class ConfigB {
}
Then, in C, where you bootstrap the application, you should import the configurations for module A and module B. At this point, any beans from A and B will be available for autowiring in C.
#Configuration
#Import(value = {ConfigA.class, ConfigB.class})
public class ConfigC {
}
Basically if you want to use #Autowired annotation on top of any attribute and use it, Obviously there should be an initialized bean in the spring context to Autowire it to your usages. So here your problem is in your spring context, there is no such bean to autowire.
So the solution is you need to have those beans inside your spring context, there are multiple ways to get this done,
The classes that you need beans auto initialized inside the spring context as #Component
Ex :
#Component
public class Car{
or you can manually have a configuration file which returns such beans
Ex :
#Bean
public Car setCarBean(){
return new Car();
}
And this bean returning should be inside a #Configuration class.
please refer
Then if you are really sure that you have done with this, then correct #ComponentScan should work
EDIT
#SpringBootApplication
#ComponentScan(basePackages = { "com.demo.xyz.A", "com.demo.xyz.B"})
public class Application {
Try to add scanBasePackages in the Application class.
The default scan is for the package in which the Application class.
#SpringBootApplication(scanBasePackages = "com.demo.xyz")
public class Application {...}

Best practice for #Value fields, Lombok, and Constructor Injection?

I'm developing a Java Spring application. I have some fields in my application which are configured using a .yml config file. I would like to import those values using an #Value annotation on the fields in question. I would also like to use the best-practice of constructor injection rather than field injection, but I would like to write my constructor using Lombok rather than manually. Is there any way to do all these things at once? As an example, this doesn't work but is similar to what I want to do:
#AllArgsConstructor
public class my service {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
...
}
In this case, what I want is Lombok to generate a constructor which sets only myDependency, and for myField to be read from my config file.
Thanks!
You need #RequiredArgsConstructor and mark myDependency as final. In this case, Lombok will generate a constructor based on 'required' final filed as argument, for example:
#RequiredArgsConstructor
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
//...
}
That is equal the following:
#Service
public class MyService {
#Value("${my.config.value}")
private String myField;
private final MyComponent myComponent;
public MyService(MyComponent myComponent) { // <= implicit injection
this.myComponent = myComponent;
}
//...
}
Since here is only one constructor, Spring inject MyComponent without the explicit use of the #Autowired annotation.
Male sure you are using at least version 1.18.4 of Lombok. And that you have your desired annotation added to the lombok.config file.
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Value
Here is your class:
#AllArgsConstructor(onConstructor = #__(#Autowired))
public class MyService{
#Value("${my.config.value}")
private String myField;
private Object myDependency;
}
And here is the lombok generated class:
public class MyService {
#Value("${my.config.value}")
private String myField;
private Object myDependency;
#Autowired
#Generated
public MyService(#Value("${my.config.value}") final String myField, final Object myDependency) {
this.myField = myField;
this.myDependency = myDependency;
}
PS: Make sure you have the lombok.config file under /src/main/java folder. I tried adding it to /src/main/resources and it did not work.
Response taken from here.

Categories