Spring #Value without annotation - java

Instead of using #Value doing this:
#Service
public class MyService{
#Value("${myValue}")
private String myValue;
}
I need to get ${myValue} without annotation, and without reading the file again. How to do it?

You can get it from Environment:
#Autowired
private Environment env;
// ...
env.getProperty("myValue");

One way to access Environment is through EnvironmentAware interface.
Example :
#Service
public class MyService implements EnvironmentAware{
private String myValue;
private Environment env;
#Override
public void setEnvironment(Environment environment) {
this.env = environment;
}
public String getMyValue() {
return env.getProperty("myValue");
}
}

Related

Intellij Idea Structural Replacement (replacing autowired annotation)

I wonder whether it's possible to replace all the Autowired fields with final ones and #RequiredArgsConstructor below the class declaration?
For instance, replace the following code
public class Controller {
#Autowired
private Reposiroty repository;
#Autowired
private Service service;
...
}
with something like that:
#RequiredArgsConstructor
public class Controller {
private final Reposiroty repository;
private final Service service;
...
}
Thanks in advance!

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 - How to inject String value to constructor?

I have following component:
#Component
public class ServiceManagerImpl implements ServiceManager {
private final ServiceA serviceA;
private final ServiceB serviceB;
private final String path;
#Autowired
protected ServiceManagerImpl(ServiceA serviceA, ServiceB serviceB, String path) {
this.serviceA= serviceA;
this.serviceB= serviceB;
this.path= path;
}
(...)
}
Now I want to create simple service to which I will inject above component with specific path value. This value should come from class with String constans:
#Component
public class ServiceManagerClientImpl implements ServiceManagerClient {
private ServiceManager serviceManager;
#Autowired
public ServiceManagerClientImpl(ServiceManager serviceManager) {
this.serviceManager = serviceManager;
}
}
Is it possible to dynamically inject simple path values on ServiceManagerClientImpl level (not from properties / yaml files)?
You can autowire the Environment class
import org.springframework.core.env.Environment;
#Autowired
private Environment environment;
You can read the enironment variable("path" in your case) using the below statement.
environment.getProperty("path");

#Autowired vs #Autowired with Setter

I have a spring boot app that I am using with the Web Plugin.
In one class I have:
package com.test.company
#Component
#RestController
public class CompanyService {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private Environment env;
And in another class I have:
package com.test.company
#Component
#RestController
public class CustomerSignUpService {
private static MongoTemplate mongoTemplate;
#Autowired
private Environment env;
#Autowired
public void setMongoTemplate(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
Both classes work but if I try to inject mongo into the CusomterSignUpService class like I did in the CompanyService class, the env is injected fine, but mongo doesn't inject and I get a null pointer exception if I try to use it.
Any thoughts? Main package is com.test.
I believe your Controller might need to look like (removed static from property):
package com.test.company
#Component
#RestController
public class CustomerSignUpService {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private Environment env;
...
...
}
You can use #Autowired both in the attribute and in the setter, but your attribute must be an instance variable, not a static one.
So do this and your code should run fine:
package com.test.company
#Component
#RestController
public class CustomerSignUpService {
private MongoTemplate mongoTemplate;
#Autowired
private Environment env;
#Autowired
public void setMongoTemplate(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
Note that the static reserved word was taken from your attribute declaration.
Remove static from the property and try it without it
package com.test.company
#Component
#RestController
public class CustomerSignUpService {
#Autowired
private MongoTemplate mongoTemplate;
#Autowired
private Environment env;
...
...
}

How to mock any services inside a #MockedBean?

Is it possible to just ignore/mock any injected dependencies inside a MockedBean?
Example:
#Service
public class MyService {
#Autowired
private MailerService mailer;
public void test1() {
//does not use mailer
}
public void test2() {
//...
mailer.send();
}
}
#Service
public class MailerService {
//I want these to be automatically mocked without explicit declaration
#Autowired
private JavaMailSender sender;
#Autowired
private SomeMoreService more;
//also these should be mocked without having to provide properties
#Value("${host}") private String host;
#Value("${user}") private String user;
#Value("${pass}") private String pass;
}
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest
public class MyServiceTest {
#Autowird
private MyService myservice;
#MockBean
private MailserService mailer;
#Test
public void test1() {
myservice.test1();
}
}
I could use #MockBean to sort out mailer injection dependency. But any service inside the mocked bean would also have to be explicitly mocked.
Question: is it possible to mock a service "away". Means, just mock the bean and don't care what's inside the #MockedBean (or automatically also mock anything inside #MockedBean)?
As for me the best way to inject mocks is to use MockitoJUnitRunner
#RunWith(MockitoJUnitRunner.class)
public class MocksTests {
#InjectMocks
private ParentService parent;
#Mock
private InnerService inner; // this will be injected into parent
//your tests
}

Categories