4

I have a Spring project, and a MongoRepository. The MongoRepository is an Interface that extends MongoRepository, just like JPA.

If I try to build my project with mvn clean install it runs Spring once. Spring tries to connect to MongoDB which is not running on my Jenkins server.

exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused: connect}

Is there a way to catch the exception? I cannot catch it on the service where I call my repository, because those methods are not executed. I think it has something to do with @autowire, but I can't figure out how to catch the exception.

The architecture:

application
  - resource (api)
  - service
  - repository extends MongoRepository

The application scans the project, the resource calls the service, the service calls the repository and the repository throws an error because it cannot connect to MongoDB.

Repository:

public interface MetingRepository extends MongoRepository<Meting, String> {
    Page<Meting> findAllByRuimteId(String ruimteId, Pageable page);
}

Service:

@Service("metingenService")
public class MetingServiceImpl implements MetingService {

  // could I try-catch this?
  @Autowired
  private MetingRepository metingRepository;

    @Override
    public Meting addMeting(Meting meting) {
      // try-catch does not solve the issue here
      return metingRepository.save(meting);
    }
  }
}

The only test I have, automatically generated:

@RunWith(SpringRunner.class)
@SpringBootTest
public class MetingenServiceApplicationTests {

    @Test
    public void contextLoads() {

    }

}

Stacktrace:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'metingResource': Unsatisfied dependency expressed through field 'metingService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'metingenService': Unsatisfied dependency expressed through field 'metingRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'metingRepository': Cannot resolve reference to bean 'mongoTemplate' while setting bean property 'mongoOperations'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoTemplate' defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.core.MongoTemplate]: Factory method 'mongoTemplate' threw exception; nested exception is org.springframework.dao.DataAccessResourceFailureException: Timed out after 30000 ms while waiting for a server that matches WritableServerSelector. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused: connect}}]; nested exception is com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches WritableServerSelector. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoSocketOpenException: Exception opening socket}, caused by {java.net.ConnectException: Connection refused: connect}}]

Randy
  • 9,419
  • 5
  • 39
  • 56
  • If you want to optionally autowire this repo you can use @Autowired(required = false) – Noixes Oct 23 '17 at 09:33
  • @Noixes even with required=false, `mvn package` runs the repository and tries to connect. I'm lost because there is no point I can catch those exceptions for as far as I know – Randy Oct 23 '17 at 09:49
  • Why is the mongodb service not reachable? – Noixes Oct 23 '17 at 09:52
  • when you say "it runs spring once"... you mean you have a unit test that is triggered by the build ? You need to show us this Unit Test, in which (depending on what you're doing in it) you need to mock the external dependencies. – alexbt Oct 23 '17 at 09:52
  • Please add the failing Unit Test to your question. Also, note that a unit test "should" not have external dependencies (such as a running MongoDB instance). – alexbt Oct 23 '17 at 09:55
  • @Noixes Because there is no database on the build server, only on production. If the MongoDB server would be down, I also want it to gracefully exit. – Randy Oct 23 '17 at 09:55
  • @Randy Did you try to introduce a "BUILD_PROFILE" and a "PRODUCTION_PROFILE"? public class MetingServiceImpl can be the production one and you also create an class of MetingService for the build_profile which does not wire to any repository. Can you tell your maven configuration to use specific profiles for different build scenarios? – Noixes Oct 23 '17 at 10:01
  • @alexbt I added the test, and you are correct this is a test issue apparently. Mocking my repository does not seem to work though :( – Randy Oct 23 '17 at 10:18
  • 1
    What's the purpose of `MetingenServiceApplicationTests` ? In most cases you shouldn't use `SpringBootTests`. Why not simple junit without Spring Context ? `@RunWith(JUnit4.class)` or `@RunWith(MockitoJUnitRunner.class)` – alexbt Oct 23 '17 at 10:26
  • @alexbt Thank you. `MockitoJUnitRunner` is what I use now and it works like a charm :) I created this project using Spring Initializr for a Spring Cloud project, and the test was included by default. – Randy Oct 23 '17 at 10:28
  • But then, you could also remove the test ;) – alexbt Oct 23 '17 at 10:28
  • @alexbt Yes you are right, but I'm going to build this test driven after I've settled the most basic buildserver dependencies, so I figured I'd keep the test alive as reference. Now with Mockito I have a proper example ;) – Randy Oct 23 '17 at 10:30

1 Answers1

1

Your unit test is trying to load the complete Spring Context. Thus, it's trying to load a valid MongoTemplate to connect to a MongoDB instance.

In most cases, you shouldn't use @SpringBootTests (which is for integration tests), instead you can do a normal JUnit test:

@RunWith(JUnit4.class) // or @RunWith(MockitoJUnitRunner.class)
public class MetingenServiceApplicationTests {
    ...
}
alexbt
  • 16,415
  • 6
  • 78
  • 87