MongoDB Autowired in custom classes - java

I've got simple structure project:
com.database.mongodb.config.MongoConfig - MongoDB configuration used in #Import
com.database.mongodb.repository.ParameterRepository - interface which extends MongoRepository
com.server.main.MainClass - Main class of my program.
I just want to use my ParameterRepository everywhere I need it, for instance, in a custom class with some tasks in package com.server.task.CustomClass. I tried:
#Autowired
private ParameterRepository repo;
But it returns NullPointerException. I tried to create abstract class Task with annotation #Component, but it also doesn't work.
How can I make it possible?
My implementations:
MongoConfig.class
#Configuration
#EnableMongoRepositories(basePackages = {"com.database.mongodb.repository"})
public class MongoConfig extends AbstractMongoConfiguration {
#Override
#Bean
public Mongo mongo() throws Exception {
return new MongoClient("localhost:27017");
}
#Override
protected String getDatabaseName() {
return "mydb";
}
}
ParameterRepository.class
#Repository
public interface ParameterRepository extends MongoRepository<Parameter, Integer> {
}
MainClass.class
#Import(MongoConfig.class)
#SpringBootApplication
public class SparkServer implements CommandLineRunner {
#Autowired
private WeatherParameterRepo weatherParameterRepo;
...

You should move your ParameterRepository to the com.server.main package (or a sub-package).
What you could also do is add #ComponentScan({"com.database.mongodb.repository", "com.server.main"}) to your MainClass class.

Related

Consider defining a bean of type 'com.example.conferencedemo.services.SessionService' in your configuration

I am trying to implement as of enterprise level, there they have folders like Repository,Service,ServiceImpl
In Services they have interface with method declaration
In ServiceImpl they have class implementing the interface of services
In Repository they have all Repository interfaces
BeanInjection is a class where we have all repositories and service classes and interfaces with
#Autowired annotation.
When I tried to implement "#Autowired" to service class getting this Error.
Tried this no help link
Tried this no help but getting loop error link
Controller.java
public class SessionController extends BeanInjectionService {
#GetMapping
public ResponseEntity<List<Session>> list(){
LOGGER.info("Request received to view the sessions");
List<Session> sessions = sessionService.findAll();
LOGGER.info("Successfully fetched all the sessions");
return new ResponseEntity<>(sessions, HttpStatus.OK);
}
SessionService.java(Interface)
public interface SessionService {
List<Session> findAll();
}
SessionServiceImpl.java(Class)
public class SessionServiceImpl extends BeanInjectionService implements SessionService {
#Override
public List<Session> findAll(){
return sessionRepository.findAll();
}
BeanInjectionService.java(Class)
public class BeanInjectionService {
#Autowired
public SessionRepository sessionRepository;
**// Error Showing here while starting application
// Consider defining a bean of type 'com.example.conferencedemo.services.SessionService' in your configuration.**
#Autowired
public SessionService sessionService;
#Autowired
public SpeakerRepository speakerRepository;
#Autowired
public SpeakerService speakerService;
}
SessionRepository.java(Interface)
public interface SessionRepository extends JpaRepository<Session,Long> {
}
Thanks in advance
I find using BeanInjectionService a little weird, but I'll answer around it.
Unless you add #Service on SessionServiceImpl, you can't autowire it.
Circular dependency - If you do step 1, it will create a circular dependency because SessionServiceImpl needs its superclass object(BeanInjectionService) to be created first. But BeanInjectionService cannot be created unless it finds an object of SessionServiceImpl.
To break the circular dependency, you have only one option. Don't extend BeanInjectionService. Rather, autowire SessionRepository directly into SessionServiceImpl.
#Service
public class SessionServiceImpl implements SessionService {
#Autowired
private SessionRepository sessionRepository;
#Override
public List<Session> findAll(){
return sessionRepository.findAll();
}
}

Multiple instances of a bean of one class filled with values from application.properties

I intend to write some HealtCheckContributors for a Spring Boot application using spring-boot-actuator. Hence, I implemented two of them. they are intended for checking the health of different apps, of course, but have a nearly identical structure, except the configuration properties, ...
SonarQube complains about that and I wonder if it is possible to have a single health check class but instantiated as many times as defined in application.properties.
An example:
application.properties:
# actuator
app1.management.baseUrl=http://localhost:10000
app1.management.name=app1HealthCheckContributor
app2.management.basUrl=http://localhost:10001
app2.management.name=app2HealthCheckContributor
HealthCheckContributor for app1:
#Slf4j
#Component("xxx")
public class App1HealthCheckContributor extends AbstractHealthIndicator {
private final App1Properties app1Properties;
public App1HealthCheckContributor(final App1Properties app1Properties) {
this.app1Properties = app1Properties;
}
#Override
protected void doHealthCheck(Health.Builder builder) {...}
}
...and this code for each HealthCheckContributor only distinct in its appXProperties.
Isn't it possible to have some kind of base class like:
#Slf4j
#Component()
public class MyHealthCheckContributor extends AbstractHealthIndicator {
private final MyProperties myProperties;
public MyHealthCheckContributor(final MyProperties myProperties) {
this.myProperties = myProperties;
}
#Override
protected void doHealthCheck(Health.Builder builder) {...}
}
and let Spring Boot take care of instantiating two HealthCheckContributors (in our case App1HealthCheckContributor and App2HealthCheckContributor)?
This would eliminate code duplication.
An example of the properties class file:
#Slf4j
#Data
#ConfigurationProperties(prefix = "app1.management")
public class App1Properties {
private String baseUrl;
private String ...;
}
How can I achieve this and how must an application.properties file looks like to achieve what I intend to do?
The final question: How to test multiple instance creation of a bean of one class filled with values from application.properties?
Assuming the code in doHealthCheck is exactly the same for all apps to be checked you could do the following.
You would start by creating a single health check class:
#Slf4j
public class AppHealthCheckContributor extends AbstractHealthIndicator {
private final AppProperties appProperties;
public App1HealthCheckContributor(final AppProperties appProperties) {
this.appProperties = appProperties;
}
#Override
protected void doHealthCheck(Health.Builder builder) {...}
}
And the properties model as follows:
#Slf4j
#Data
public class AppProperties {
private String baseUrl;
private String name;
}
This means that the configuration would be something like the following (in application.yml):
health-check:
apps:
- baseUrl: http://localhost:10000
name: app1
- baseUrl: http://localhost:10001
name: app2
Finally, you would need to create a bean for each app and register them in the application context:
#Slf4j
#Data
#Configuration
#ConfigurationProperties(prefix = "health-check")
public class AllAppPropertiesConfiguration {
private List<AppProperties> apps;
#Autowired
private GenericApplicationContext applicationContext;
#PostConstruct
fun init() {
for (AppProperties app : apps) {
applicationContext.registerBean(app.getName(), AppHealthCheckContributor.class, app);
}
}
}

SpringBoot Autowiring a generic type fails because of multiple possible beans

I'm trying to create a class that Autowire an object of type T.
#component
public class TaskScheduler<T extends TaskService>{
#Autowired
private T taskService;
}
the problem is that I have two components that extend TaskService.
#component
public class firstTaskService extends TaskService {
}
and
#component
public class secondTaskService extends TaskService {
}
so when this line is executed (ts is being created)
#Autowired
TaskScheduler<firstTaskService> ts;
I get this error :
Description:
Parameter 1 of constructor in TaskScheduler required a single bean, but 2 were found
the message I got suggested this :
Action: Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify
the bean that should be consumed.
But from what I understood, the #Primary and #Qualifier annotations make me choose 1 of the components, which not what I want because I want to use firstTaskService and secondTaskService with that same class (TaskScheduler).
How could this be done?
Edit: Clarification: My objective is to reuse the TaskScheduler class with different classes that extend the TaskService class (not to use multiple classes that extend TaskService together in TaskScheduler).
If you want to autowire all beans that extends TaskService maybe you should change the autowired field to a List:
#Component
public class TaskScheduler<T extends TaskService>{
#Autowired
private List<T> taskService;
}
In this way Spring should put in the List all autowireable beans that extends TaskService.
EDIT: since you want to dinamically select the type of TaskService the only way I've found is the following. First, redefine your TaskScheduler:
public class TaskScheduler <T extends TaskService>{
private T taskService;
public void setTaskService(T taskService) {
this.taskService = taskService;
}
}
Your TaskService and related subclasses should remain untouched. Set up a configuration class as it follows:
#Configuration
public class TaskConf {
#Autowired
private FirstTaskService firstTaskService;
#Autowired
private SecondTaskService secondTaskService;
#Bean
public TaskScheduler<FirstTaskService> firstTaskServiceTaskScheduler(){
TaskScheduler<FirstTaskService> t = new TaskScheduler<>();
t.setTaskService(firstTaskService);
return t;
}
#Bean
public TaskScheduler<SecondTaskService> secondTaskServiceTaskScheduler(){
TaskScheduler<SecondTaskService> t = new TaskScheduler<>();
t.setTaskService(secondTaskService);
return t;
}
}
And then test your TaskScheduler in this way:
#Autowired
TaskScheduler<firstTaskService> ts;

Mockito Spring Camel #Autowire fail

I'm trying to unit test a camel route. The route under test extends a custom abstract RouteBuilder (I know about favouring composition over inheritance - this is maintenance code). I've set up my test as #Roman Vottner did over here. Everything works (is initialized) until I hit the first abstract class up the hierarchy. It has an #Autowired class which wasn't initialized (is null) even though it was mocked and #Autowired when the test started. Any ideas on how to solve my injection problem?
#RunWith(CamelSpringRunner.class)
#BootstrapWith(CamelTestContextBootstrapper.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = {FooRouteTest.ContextConfig.class})
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class FooRouteTest {
#Configuration
#PropertySource({"classpath:some.properties", "classpath:environment.properties"})
public static class ContextConfig extends CamelConfiguration {
#Bean
public UserServices userServices() {
return mock(UserServices.class);
} //and many more of the like
}
#Autowired
private UserServices userServices; //and all the others too
#Test
public void testAfoo() throws Exception {
//....
template.setDefaultEndpointUri("direct://getTheData");
template.sendBody(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonNode));
//...
}
}
in the abstract super class while debugging:
#Autowired
public ClientServices clientServices;
//...
String clientNumber=clientServices.getLoggedInNumber(); //clientServices is null and not mocked!
//...
Solved this by explicitly declaring FooRoute as a bean:
#Bean
public FooRoute fooRoute(){
return new FooRoute();
}
#Override
public List<RouteBuilder> routes() {
final List<RouteBuilder> routes = new ArrayList<>();
routes.add(fooRoute());
return routes;
}

Not able to use spring dependency injection across various classes for TestNG using java annotations(JSR 330 Standard Annotations)

I have a service which I am trying to inject across various classes in my tests but I am getting its instance as null.
My config interface:
MyService.java
public interface MyService {
public String getHostUri();
}
My implementation class of this interface: MyServiceImpl.java
public class MyServiceImpl implements MyService {
private static final String BASE_HOST_URI_CONFIG = "localhost:4444";
#Override
public String getHostUri() {
return BASE_HOST_URI_CONFIG;
}
My Spring configuration class with the bean:
#Configuration
public class AutomationSpringConfig {
#Bean
public MyService getMyService(){
return new MyServiceImpl();
}
}
My testNG class:
#ContextConfiguration(classes=AutomationSpringConfig.class ,loader =AnnotationConfigContextLoader.class)
public class BasicAutomatedTest extends AbstractTestNGSpringContextTests {
private static final Logger LOGGER = Logger.getLogger(BasicAutomatedTest.class);
#Inject
private MyService myService;
#Test
public void basicTest {
Setup setup = new Setup();
LOGGER.info(myService.getHostUri());
LOGGER.info(setup.myService.getHostUri());
}
}
My helper class in which I am not able to get the injection:
public class Setup {
#Inject
public MyService myService;
}
So when I try to get the hostUri via the setup object in the BasicAutomatedTest's basicTest method I get a NullPointerException.
So I am not able to inject the MyService bean in the Setup class.
In order to use annotations you need to specify that behaviour in your beans XML configuration file. Something like this:
<context:component-scan base-package="your.base.package"/>
<context:annotation-config/>
Hope it helps!

Categories