1

I've Project A with the following specs:

  • Jar
  • Java 7
  • Spring 4.2.0 + Spring Security
  • Spring Data JPA, Oracle, H2 (w/ scope test)

I've Project B with the following specs:

  • War
  • Java 8
  • Tomcat 8.5.x
  • Spring Boot 2
  • Spring 5 + Spring Security

Both projects successfully build and run individually. I want Project A be a dependency of Project B. I'm using IntelliJ and followed steps available on the web (#1, #2), but here's the gist of what I did:

File -> Project Structure

  • Project -> Ensure Project A's SDK + Project level are set to Java 8
  • Modules -> Select Project A -> Ensure SDK + Project level are set to Java 8 for Sources + Dependencies
  • Modules -> Click + button > Import Module -> Select Project A's pom.xml -> Follow import steps
  • Modules -> Select Project B -> Ensure SDK + Project level are set to Java 8 for Sources + Dependencies
  • Modules -> Select Project A -> Dependencies -> Click + button > Add Module Dependency -> Select Project A
  • Add Project A as dependency into Project B's pom.xml, and match dependency's version with Project A's version (from pom)

I successfully run "mvn clean install". When I run Project B on Tomcat, I get:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-08-14 15:01:03.796 ERROR 15888 --- [on(3)-127.0.0.1] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.

Reason: Failed to determine a suitable driver class

I'm not sure why Project A's JPA/DB config is causing issues in Project B, even though Project A works fine by itself. But, after some research, I added the following annotation to my SpringBoot Application:

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

and this is what I ended up with:

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class ProjectB extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(ProjectB.class);
    }

    public static void main(String[] args) {
        SpringApplication.run(ProjectB.class, args);
    }

}

I successfully run "mvn clean install". I run Project B again, and it launches successfully! when I try to reference anything from Project A (i.e. A service), it builds fine, but when launching I get the following:

SEVERE [RMI TCP Connection(3)-127.0.0.1] org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start: 
 org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:167)

    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:754)
***************************
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:730)
APPLICATION FAILED TO START
***************************
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)

    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1736)
Description:
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
Parameter 0 of constructor in com.projectB.controller.ControllerName required a bean of type 'com.projecta.service.ServiceName' that could not be found.
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

    at java.lang.reflect.Method.invoke(Method.java:498)

    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300)
Action:
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)

Consider defining a bean of type 'com.projecta.service.ServiceName' in your configuration.

Is it even possible to import Spring module into Spring Boot 2? If so, what am I missing? If not, what're my options?


Edit 1: Add Simple service (Project A) + controller (Project B)

// Controller in Project B
@RestController
@RequestMapping("/api")
public class SimpleController {
    private SimpleService simpleService;

    @Autowired
    public SimpleController(SimpleService simpleService) {
        this.simpleService = simpleService;
    }

    @GetMapping
    public ResponseEntity<?> generateAndSendEmail() {
        boolean success = simpleService.callSimpleService();
        if (success) {
            return new ResponseEntity<>(OK);
        }
        return new ResponseEntity<>(INTERNAL_SERVER_ERROR);
    }
}

// Service in Project A
@Service
public class SimpleService {
    public boolean callSimpleService() {
        return true;
    }
}
  • How are you configuring services from ProjectA in ProjectB? – Compass Aug 14 '18 at 20:15
  • @Compass Since Project A is a dependency, I just reference like so: private ServiceName serviceName; in Project B controller and IntelliJ imports it from the right place. Even after that, I can build the project fine. It gives the error when launching it. – Silent Knight Aug 14 '18 at 20:40
  • How are you configuring ServiceName? Is it Autowired or does it have additional dependencies that it needs help wiring? If you have configurations for ServiceName that don't reside in Project B, they will not wire properly. – Compass Aug 14 '18 at 20:43
  • Oh. It is Autowired – Silent Knight Aug 14 '18 at 20:48
  • When you autowire a Service that requires configuration, you need to define a @Bean that configures the Service. Please provide your ServiceName's fields. – Compass Aug 14 '18 at 20:56
  • It works without issues when I make project A depedency of another project, although the other project is also Spring 4 project, rather than Spring Boot 2 + Spring 5. I will update the post and add as much code as I can soon. – Silent Knight Aug 14 '18 at 21:23
  • You are asking for dependency hell by doing this. Project A needs updated/branched/a version for boot 2.0. Spring > Spring Boot > Spring Cloud etc. all have specific releases, your classpath will be a mix of conflicting classes which will at somepoint result in `methodNotFound` exceptions due to trying to mix two incompatible dependencies. – Darren Forsythe Aug 15 '18 at 16:42

2 Answers2

0

When you include projectA as a maven dependency in Project B, all the class files in projectA become available on your classpath. Nothing more.

When you add a service as an autowired dependency, the spring container (of project B) expects an implementing bean to be available in the context.

The spring context will not be able to find an implementation of ServiceA, because it does not scan the packages of projectA. The default implementation of @ComponentScan in projectB will only recognize beans declared in sub packages of Project B. To make the beans from Project A to be available in Project B you need to add an explicit @ComponentScan in Project B's main class instructing spring to scan the packages in Project A.

It is also advisable to remove Spring 4.X dependencies from Project A's pom file

Monish Sen
  • 1,773
  • 3
  • 20
  • 32
  • I tried @ComponentScan too, like so: @ComponentScan({"com.projecta","com.probjectb"}), but that didn't resolve anything. Project A is a dependency in other Spring-only projects too. – Silent Knight Aug 14 '18 at 21:22
0

Have you tried manually creating the service as a bean your spring boot app? Inside your main class:

@Bean
public SimpleService simpleService() {
    return new SimpleService();
}
Mike
  • 4,722
  • 1
  • 27
  • 40