0

I am writing a Java Spring based Library. I have written junit tests for them. The problem which I have is that though my beans are getting printed, they are not getting autowired properly. They are null.

Here is the code.

@Test
public void test() {
    System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));

    try{
    DBClient dbClient = new DBClient();
    dbClient.doSomething();
    }catch(Exception e){
        e.printStackTrace();
    }
}

Here is my DBClient code:

    @Autowired
@Qualifier("UserActivityRepositoryService")
private UserActivityRepositoryService userRepositoryService;

public void doSomething() {
    System.out.println("Inside db client. Getting the count");
    System.out.println(this.userRepositoryService.count());
}

This is my UserRepositoryService class code

@Service
@Qualifier("UserActivityRepositoryService")
public class UserActivityRepositoryService implements IRepoClient<UserActivity>{

private UserActivityRepository repo;

@Autowired
public void setUserActivityRepository(UserActivityRepository repo) {
    this.repo = repo;
}

public void create(UserActivity userActivity) {
    repo.save(userActivity);        

}

@Override
public UserActivity save(UserActivity entity) {
    // TODO Auto-generated method stub
    System.out.println("Creating the documenht");
    try{
    repo.save(entity);
    }catch(Exception e){
        e.printStackTrace();
    }
    System.out.println("userActivity" + entity);
    return null;
}

@Override
public Iterable<UserActivity> save(Iterable<UserActivity> entities) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public UserActivity findOne(String id) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public boolean exists(String id) {
    // TODO Auto-generated method stub
    return false;
}

@Override
public Iterable<UserActivity> findAll() {
    // TODO Auto-generated method stub
    return null;
}

@Override
public Iterable<UserActivity> findAll(Iterable<String> ids) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void delete(String id) {
    // TODO Auto-generated method stub

}

@Override
public void delete(UserActivity entity) {
    // TODO Auto-generated method stub

}

@Override
public void delete(Iterable<? extends UserActivity> entities) {
    // TODO Auto-generated method stub

}

@Override
public void deleteAll() {
    // TODO Auto-generated method stub

}

@Override
public long count() {
    // TODO Auto-generated method stub
    return 0;
}
}

Here is my output: [org.springframework.context.annotation.internalConfigurationAnnotationProcessor, org.springframework.context.annotation.internalAutowiredAnnotationProcessor, org.springframework.context.annotation.internalRequiredAnnotationProcessor, org.springframework.context.annotation.internalCommonAnnotationProcessor, org.springframework.context.event.internalEventListenerProcessor, org.springframework.context.event.internalEventListenerFactory, myCouchbaseConfig, integrationTestConfig, org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor, org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor, CBRepoFactory, repoFactoryBuilder, config, userActivityRepositoryService, couchbaseBucket, couchbaseCluster, couchbaseClusterInfo, couchbaseEnv, couchbaseTranslationService, couchbaseIndexManager, couchbaseMappingConverter, couchbaseTemplate, couchbaseRepositoryOperationsMapping, couchbaseMappingContext, couchbaseCustomConversions, org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension#0, userActivityRepository] java.lang.NullPointerException Inside db client. Getting the count

Can anyone tell me what I am doing wrong.

surya
  • 171
  • 2
  • 12

2 Answers2

3

Classic Spring newbie mistake. I've seen it a thousand times.

You autowired a class DBClient, expecting that Spring will handle all the dependency injection for you.

Then you instantiate your own instance by calling new:

DBClient dbClient = new DBClient();

Once you call new, it's out of Spring's control. There is no auto wiring going on here, UserActivityRepositoryService is null.

You have to choose: Either give Spring control of everything or you do it.

If you're testing, I'd recommend using mocks and leaving Spring out of your JUnit testing.

I'd also recommend that you prefer constructor injection over getter/setter. That way you can do it in code when you need to, like when you're writing unit tests.

Looks like you're trying to write a data service. I'd recommend that you forget about your framework and use Spring Boot. It already does this for you.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • Understood. I am writing a library and the interface is just a factory and should return an autowired instance of a bean. How do I do that? – surya Aug 17 '17 at 20:48
  • Why are you writing a factory when the Spring Bean factory is already available to you? You're wrapping a framework with a framework? – duffymo Aug 17 '17 at 20:58
  • Can't imagine why this was downvoted. Would whoever did it care to explain why? – duffymo Aug 17 '17 at 20:58
  • I dont want to provide a RESTFul Service. I really want to expose a factory which returns an instance for the UserActivityRepositoryService. – surya Aug 17 '17 at 23:41
  • I don't know what "expose" means. Is this an in-memory object that your app uses? Is it a web object? Spring Boot does it better than you do. Perhaps you can learn something by looking at the way they do it. – duffymo Aug 18 '17 at 00:02
0

You need to change your test like this (as duffymo already said):

@Autowired
private DBClient dbClient;   

@Test
public void test() {
    System.out.println(Arrays.asList(applicationContext.getBeanDefinitionNames()));

    try{
        dbClient.doSomething();
    }catch(Exception e){
        e.printStackTrace();
    }
}
flexguse
  • 479
  • 6
  • 22
  • This only works if Spring is set up to autowire the tests. This is not enough. – duffymo Aug 17 '17 at 22:08
  • As surya is able to access the applicationContext I supposed the test already is configured with '@RunWith(SpringRunner.class)'. With the given incomplete code fragments it is not possible to see what is given in the test and what is missing. – flexguse Aug 18 '17 at 06:47
  • I assume the worst, given that surya doesn't understand how autowiring works. – duffymo Aug 18 '17 at 11:45