How to prevent instantiation of original mongo configuration bean in SpringBootTest? - spring

I would like to use embedded MongoDB for my integration tests and have added the flapdoodle dependency in pom.xml.
However, I have the following config class that is used to connect to an actual MongoDB instance:
#Configuration
public class DbConfig extends AbstractMongoClientConfiguration {
#Value("${spring.data.mongodb.username}")
private String username;
#Value("${spring.data.mongodb.password}")
private String password;
#Value("${spring.data.mongodb.database}")
private String database;
#Value("${spring.data.mongodb.host}")
private String host;
#Value("${spring.data.mongodb.port}")
private String port;
#Override
public MongoClient mongoClient() {
String url = "mongodb://" + username + ":" + password + "#" + host + ":" + port + "/" + database;
MongoClientSettings mongoClientSettings = MongoClientSettings.builder().applyConnectionString(new ConnectionString(url).build();
return MongoClients.create(mongoClientSettings);
}
}
When I do not provide the spring data mongodb parameters in my tests' application.yml and run the SpringbootTest, NoSuchBeanDefinitionException is thrown. On the other hand, if I do specify the spring data parameters, the tests connect to the real mongodb instance instead.
How can I prevent/override the instantiation of the DbConfig bean so that embedded MongoDb can be used?

Related

Spring boot junit test #JpaDataTest not working due to missing dependency

I'm trying to write a test using my actual configuration.
In the normal spring context, I'm loading the dataSource using a #Autowired service that decrypts the database password from the properties.
It looks like this
#Configuration
public class DataBaseConfig {
#Value("${swat.datasource.url}")
private String dbURL;
#Value("${swat.datasource.driver-class-name}")
private String driverName;
#Value("${swat.datasource.username}")
private String userName;
#Value("${swat.datasource.password}")
private String hashedPassword;
#Autowired
EncryptionService encryptionService;
#Bean
public DataSource primaryDataSource() {
String password = encryptionService.decriptPassword(hashedPassword);
return DataSourceBuilder.create().url(dbURL).driverClassName(driverName).username(userName).password(password).build();
}
im now trying to run a test using #JpaDataTest (not the #SpringBootTest)
doing the following
#RunWith(SpringRunner.class)
#DataJpaTest
#AutoConfigureTestDatabase(replace=Replace.NONE)
#Import(DataBaseConfig.class)
#TestPropertySource(value = "file:./executor.properties")
public class NewDeviceTest {
#Autowired
NewDeviceService newDeviceService;
#Test
public void loadNewDevices() {
List<NewDevice> devices = newDeviceService.findAll();
assertEquals(1, devices.size());
assertTrue(devices.get(0).isNew());
}
}
im getting a problem since the EncryptionService in the DataBaseConfig cannot be resolved
how do i tell the Test to first load this
i tried
#ComponentScan("com.wisemon.compliance.executor.service")
but it loads all the components and some of them have a behaviour that i dont want in my test (load initial db data... scheduling etc)

AutoWired getProperty returning null

I have 2 classes in which i am getting the getProperty of autowired class as null
I will post my classes and explain the problem below
I have used autowiring but i am getting my output as null
Connection.java
#Component
public class Connection {
private static org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Connection.class);
Logger basiclogger = Logger.getLogger("Main");
public CloseableHttpClient httpClient;
public static String Server;
public static String service;
public static String User;
public static String Password;
#Autowired
public Connection(#Value("${Server}") String Server, #Value("${service}") String service,
#Value("${User}") String User,#Value("${Password}") String Password)
{
Connection.Server = Server;
Connection.service = service;
Connection.User = User;
Connection.Password = Password;
}
public Connection(){
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
public void setHttpClient(CloseableHttpClient httpClient) {
this.httpClient = httpClient;
}
public CloseableHttpClient makeConnection() {
AuthenticatedClientBuilder builder = AuthenticatedClientBuilder.create(serviceProvider)
.addServer(Server).setUser(User)
.setPassword(Password);
httpClient = builder.build();
basiclogger.info("Connection is Established SuccessFully");
return httpClient;
}
}
}
In Spring XML
<bean id="conn" class="com.java.Connection"
scope="prototype"/>
In Main
#Autowired(required = true)
Connection connection;
new ClassPathXmlApplicationContext(new String[] {"Spring-batch-context.xml"});
Connection connection = (Connection)context.getBean("conn");
connection.getHttpClient();
System.out.println("***********"+connection.getHttpClient()+"***********");
But i am getting connection.getHttpClient() as null
Can someone please help me
Thanks in advnace!!!!!!!!
From :
Connection connection = (Connection)context.getBean("conn");
Remove #Autowired on Connection in main method and change to:
#Autowired
BeanFactory beanFactory;
Connection connection = beanFactory.getBean(Connection.class, "args");
#Scope(value = "prototype") means that Spring will not instantiate the bean right on start, but will do it later on demand.
Update:
Here is the Javadoc of beanFactory.getBean()
getBean(java.lang.Class<T> requiredType, java.lang.Object... args)
throws BeansException
Return an instance, which may be shared or independent, of the specified bean.
Allows for specifying explicit constructor arguments / factory method
arguments, overriding the specified default arguments (if any) in the
bean definition.
This method goes into ListableBeanFactory by-type lookup territory but
may also be translated into a conventional by-name lookup based on the
name of the given type. For more extensive retrieval operations across
sets of beans, use ListableBeanFactory and/or BeanFactoryUtils.
Parameters:
requiredType - type the bean must match; can be an interface or superclass
args - arguments to use when creating a bean instance using explicit arguments
Returns: an instance of the bean
Throws:
NoSuchBeanDefinitionException - if there is no such bean definition
BeanDefinitionStoreException - if arguments have been given but the affected bean isn't a prototype
BeansException - if the bean could not be created
Further, read here: BeanFactory

Spring Boot Use Custom Properties Service

I am working on a legacy project that has its own PropertyService class that manages the reloadable properties and so on.
The thing works pretty much OK, but the problem is now I have this property service, for my project, and an application.yml for the spring boot related properties.
The question is: is there a way to tell spring boot to load properties from something like a properties provider - a custom class or an adapter of sort ?
In this way I could manage my properties only through the existing module
Thank you for your help !
Try #ConfigurationProperties to customize the properties loading (see the example)
The code example
#Configuration
#ConfigurationProperties(locations = "classpath:mail.properties", prefix = "mail")
public class MailConfiguration {
public static class Smtp {
private boolean auth;
private boolean starttlsEnable;
// ... getters and setters
}
#NotBlank
private String host;
private int port;
private String from;
private String username;
private String password;
#NotNull
private Smtp smtp;
// ... getters and setters
#Bean
public JavaMailSender javaMailSender() {
// omitted for readability
}
}
So you define a bean which in fact returns properties

Spring Dependency Injection with anotaation in constructor with parameter

I have below Spring class which I want to load with Spring DI. With default-constructor it's working as expected but can anyone tell me the annotation details and syntax with constructor with string arguments. This string arguments are run time.
I have tried with XML configuration "constrctor args" and working as expected.
public someclass(String hostName, int port, String user, String password) {
this.user = user;
this.password = password;
}
I assume your fields(hastName, port, user and password) are coming from properties file like for a server configuration.
#Component
public class SomeClass {
#Autowired
public someclass(#Value("${server.hostName}") String hostName, #Value("${server.port}") int port, #Value("${server.user}") String user, #Value("${server.passowrd}") String password ) {
this.user = user;
this.password = password;
}
}
If your params aren't static values, you would use programmatic way.
You need to autowire application context before you create instance of your bean.
#Autowired
private ApplicationContext ctx;
Then, create your bean instance and register it to application context,
BeanDefinitionRegistry registry = ((BeanDefinitionRegistry) ctx.getFactory());
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(SomeClass.class);
beanDefinition.setLazyInit(false);
beanDefinition.setAbstract(false);
beanDefinition.setAutowireCandidate(true);
beanDefinition.setScope("singleton"); // you should deal your scope.
ConstructorArgumentValues constructor = beanDefinition.getConstructorArgumentValues();
constructor.addIndexedArgumentValue(0, hostName);
constructor.addIndexedArgumentValue(1, port);
constructor.addIndexedArgumentValue(3, user);
constructor.addIndexedArgumentValue(4, password);
String beanName = "someclass"; // give a name to your bean
BeanComponentDefinition definition = new BeanComponentDefinition(beanDefinition, beanName);
BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry);
Be careful while dealing your bean scope. You may use request or session scope according your structure.
At last, you can autowire SomeClass in other classes;
#Autowired
public SomeClass someClass;

Correct scope for spring beans on Rest Service

I'm creating a REST service using RestEasy and Spring 4.
The service is basically an endpoint for a complex batch process. So clients call the service passing a bunch of parameters and then the processing is triggered.
As there are many parameters that are initially passed to the service, and those parameters are used pretty much everywhere in the system, I've chosen to create a 'helper' bean that will hold the parameters, then every other bean can autowire the 'parameter bean' and use it.
example:
the url called by the client would be: http://localhost/rest/service/execute?processType=A&initialDate=20141220&finalDate=20141231......
The REST Service endpoint would be something like:
#Path("/service")
public class RESTService {
#Autowired
private RequestParams params;
#Autowired
private ProcessOrchestrator orchestrator;
#POST
#Path("/execute")
#Produces(MediaType.TEXT_PLAIN)
public Response executa(
#NotNull #QueryParam("processType") String processType,
#NotNull #QueryParam("initialDate") String initialDate,
#NotNull #QueryParam("finalDate") String finalDate,
...
) {
params.setProcessType(processType);
params.setInitialDate(initialDate);
params.setFinalDate(finalDate);
orchestrator.triggerBatchProcess();
}
}
The RequestParams bean will only hold the parameters values:
#Component
public class RESTService {
private String processType;
private String initialDate;
private String finalDate;
...
// getters and setters
}
And the other beans would #Autowire the params bean and use its parameters:
#Component
public class DataProcessor {
#Autowire
private RequestParams params;
//...
}
#Component
public class DataConverter {
#Autowire
private RequestParams params;
//...
}
#Component
public class FileWritter {
#Autowire
private RequestParams params;
//...
}
The design looks correct, right? Now, my concern is: how do I make sure that a new RequestParams instance is created every time the service is called? Do I need to declare a scope ("request" for instance) for all my beans?

Resources