Spring - How to inject String value to constructor? - java

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");

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!

Mockito: injected component returns null

I have an issue. I use Mockito Framework to test a service but I have to inject another service into it in order to work. The problem is that I get a NullPonterException when I try to use the second service. Is there a special way to inject the different mock objects into the two services. My code currently looks like this:
#ExtendWith(MockitoExtension.class)
public class Service1Test {
#Mock
Repository1 repository1;
#Mock
Repository2 repository2;
#Mock
Repository3 repository3;
#Mock
Repository4 repository4;
#InjectMocks
Service1 service1;
#InjectMocks
Service2 service2;
}
#Service
public class Service1Impl implements Service1 {
private final Repository1 repository1;
private final Repository2 repository2;
#Autowired
public Service1Impl (Repository1 repository1, Repository2 repository2) {
this.repository1; = repository1;
this.repository2; = repository2;
}
}
#Service
public class Service2Impl implements Service2 {
private final Repository1 repository1;
private final Repository2 repository2;
private final Repository3 repository3;
private final Repository4 repository4;
#Autowired
public PostServiceImpl(PostRepository postRepository, CommentRepository commentRepository, TagRepository tagRepository, CategoryRepository categoryRepository) {
this.postRepository = postRepository;
this.commentRepository = commentRepository;
this.tagRepository = tagRepository;
this.categoryRepository = categoryRepository;
}
}

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.

Mock private field being initialized by OSGI Felix container

I'm trying to mock a private field in my class which is being initialized by OSGI container in which my app is running. I'm putting a sample code for reference, any clue on this please:
import org.apache.felix.scr.annotations.*
#Component (name = "MyServiceImpl ", ds = true, immediate = true)
#Service
public class MyServiceImpl extends MyBasee implements MyService {
#Reference (name = "MyOtherService", bind = "bind", unbind = "unbind", policy = ReferencePolicy.STATIC)
private MyOtherService myServiceRegistryConsumer;
}
Here I'm trying to mock private field MyOtherService myServiceRegistryConsumer
With Mockito you can mock and inject fields using the #InjectMocksannotation.
#RunWith(MockitoJUnitRunner.class)
public class AppTest {
#Mock
private MyOtherService myServiceRegistryConsumer;
#InjectMocks
private MyServiceImpl myServiceImpl;
#Test
public void testSomething() {
// e.g. define behavior for the injected field
when(myServiceRegistryConsumer.methodA()).thenReturn(/* mocked return value */);
}
}

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