title: Spring Boot Maven Multi-Module Configuration Structure
body: <p>I have an existing "legacy" Spring 4 RESTful application that works great.  I say "legacy" because it's not using Spring Boot.   So, now I am creating a new Spring Boot application from scratch and bring over the java code packages.</p>
  
  <p>The old spring configuration was like this:</p>
  
  <pre><code>Maven Parent Module: phonebook (appname)
  + - pom.xml
  |
  +--- phonebook-entity
  + - pom.xml - compiles to a Jar
  +---+ src
  +---+----+-main
  +---+----+-----+ java
  +---+----+-----+ resources
                        phonebook-entity-context.xml
  +---+----+-test
  +---+----+-----+ java
  +---+----+-----+ resources
  |
  +--- phonebook-dao
  + - pom.xml - compiles to a Jar
  +---+ src
  +---+----+-main
  +---+----+-----+ java
  +---+----+-----+ resources
                        phonebook-dao-context.xml
  +---+----+-test
  +---+----+-----+ java
  +---+----+-----+ resources
  |
  +--- phonebook-service
   + - pom.xml - compiles to a Jar
  +---+ src
  +---+----+-main
  +---+----+-----+ java
  +---+----+-----+ resources
                        phonebook-service-context.xml
  +---+----+-test
  +---+----+-----+ java
  +---+----+-----+ resources
  |
  +--- phonebook-ws
   + - pom.xml - compiles to a Jar
  +---+ src
  +---+----+-main
  +---+----+-----+ java
  +---+----+-----+ webapp
  +---+----+-----+ resources
                        phonebook-ws-context.xml
  +---+----+-test
  +---+----+-----+ java
  +---+----+-----+ resources
  </code></pre>
  
  <p>So, this is the layout of the project structure.   This can also be seen here:     <a href="https://github.com/tjholmes66/phonebook-backend-rest" rel="nofollow noreferrer">https://github.com/tjholmes66/phonebook-backend-rest</a></p>
  
  <p>The first old application context file in XML is named: phonebook-entity-context.xml and has most of the configuration in it as follows:</p>
  
  <pre><code>&lt;bean
      class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" /&gt;
  &lt;bean
      class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /&gt;
  
  &lt;context:annotation-config /&gt;
  &lt;context:component-scan base-package="com.opensource.products.phonebook.server" /&gt;
  
  &lt;bean id="dataSource"
      class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
      &lt;property name="driverClassName"&gt;
          &lt;value&gt;${hibernate.connection.driver.class}&lt;/value&gt;
      &lt;/property&gt;
      &lt;property name="url"&gt;
          &lt;value&gt;${hibernate.connection.url}&lt;/value&gt;
      &lt;/property&gt;
      &lt;property name="username"&gt;
          &lt;value&gt;${hibernate.connection.username}&lt;/value&gt;
      &lt;/property&gt;
      &lt;property name="password"&gt;
          &lt;value&gt;${hibernate.connection.password}&lt;/value&gt;
      &lt;/property&gt;
  &lt;/bean&gt;
  
  &lt;!-- Hibernate SessionFactory --&gt;
  &lt;bean id="sessionFactory"
      class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"&gt;
  
      &lt;property name="packagesToScan"
          value="com.opensource.products.phonebook.server.domain" /&gt;
  
      &lt;property name="hibernateProperties"&gt;
          &lt;props&gt;
              &lt;prop key="hibernate.dialect"&gt;${hibernate.dialect}&lt;/prop&gt;
              &lt;prop key="hibernate.show_sql"&gt;${hibernate.show_sql}&lt;/prop&gt;
              &lt;prop key="hibernate.cglib.use_reflection_optimizer"&gt;${hibernate.cglib.use_reflection_optimizer}&lt;/prop&gt;
              &lt;prop key="useUnicode"&gt;true&lt;/prop&gt;
              &lt;prop key="useLegacyDatetimeCode"&gt;false&lt;/prop&gt;
              &lt;prop key="serverTimezone"&gt;UTC&lt;/prop&gt;
          &lt;/props&gt;
      &lt;/property&gt;
      &lt;property name="dataSource" ref="dataSource" /&gt;
  &lt;/bean&gt;
  
  &lt;bean id="transactionManager"
      class="org.springframework.orm.hibernate5.HibernateTransactionManager"&gt;
      &lt;property name="sessionFactory" ref="sessionFactory" /&gt;
  &lt;/bean&gt;
  
  &lt;!-- enable the configuration of transactional behavior based on annotations --&gt;
  &lt;tx:annotation-driven transaction-manager="transactionManager" /&gt;
  
  &lt;beans profile="default"&gt;
      &lt;context:property-placeholder
          location="file:/opt/phonebook/phonebook-ws.properties" /&gt;
  &lt;/beans&gt;
  </code></pre>
  
  <p>This works great and this module correctly compiles into a JAR and since it is all hibernate entities which are POJO's, no testing needs to be done.</p>
  
  <p>The next module which is the phonebook-dao, has a very similar structure to the entity module.  The pom.xml here does include the appname-entity.jar which works great.   This module has it's own application context xml file under:  /src/main/resources/phonebook-dao.xml and has this configuration:</p>
  
  <pre><code>&lt;import resource="classpath:/phonebook-entity-context.xml" /&gt;
  </code></pre>
  
  <p>This means it is pulling ALL the configuration from the previous JAR.
  I can then write my tests as follows:</p>
  
  <pre><code>@RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration(locations =
  { "classpath:/spring/phonebook-dao-context.xml" })
  @Transactional
  public class ContactDaoTest extends TestCase
  { ... }
  </code></pre>
  
  <p>And this works great .... this compiles into a JAR with the entities.jar inside of it.</p>
  
  <p>Likewise, we can repeat the process for services.<br>
  That is the pom.xml contains a dependencies to the phonebook-dao.jar.<br>
  There is also a phonebook-services.context.xml which includes the following:</p>
  
  <pre><code>&lt;import resource="classpath:/phonebook-dao-context.xml" /&gt;
  ...
  and then some beans for email configuration in this xml file.
  </code></pre>
  
  <p>The tests are also configured like:</p>
  
  <pre><code>@RunWith(SpringJUnit4ClassRunner.class)
  @ContextConfiguration(locations =
  { "classpath:/spring/phonebook-service-context.xml" })
  @Transactional
  public class ContactServiceTest extends TestCase
  { ... }
  </code></pre>
  
  <p>And these tests works great!  This compiles into a phonebook-services.jar which contains the phonebook-dao.jar which contains the phonebook-entity.jar.</p>
  
  <p>The process is repeated with the web-services level ....</p>
  
  <p>It took me a while to tweak this infrastructure and to get everything just so, so that the entities could compiled, so the dao could compile and the tests would run, the services can test and run, and the controllers can test and run.  This is my complete RESTful Phonebook back-end done with Spring "Legacy" ... meaning it was done without Spring Boot.</p>
  
  <p>Now I am learning Spring Boot, and porting this application to Spring Boot.
  This new project is located:<br>
  <a href="https://github.com/tjholmes66/spring-boot-phone-book" rel="nofollow noreferrer">https://github.com/tjholmes66/spring-boot-phone-book</a></p>
  
  <p>I am trying the same structure as I did with the Spring "Legacy" Phonebook.
  I have had some success with all the research I have done, so that I have a parent project which defines the package structure, and then the parent pom references Spring Boot as it's parent.</p>
  
  <p>The first layer is the springboot-phonebook-entity module.
  There is a /src/main/resources/application.properties file that is a standard properties file with database information and such.  I don't have issues with this layer, it compiles fine, and there are no Spring errors, and no tests to execute here.</p>
  
  <p>In the second layer, springboot-phonebook-dao module
  The pom.xml DOES contain a dependency to: springboot-phonebook-entity.jar
  And it is this jar file that contains the application.properties. 
  There is no application.properties here except in the jar, and there is no SpringBootApplication defined here also.   I just have a bunch of interfaces under package:  com.tomholmes.springboot.phonebook.server.dao;</p>
  
  <p>Now, in order to test this, I am doing the following:</p>
  
  <pre><code>@SpringBootApplication
  @PropertySource(value = "classpath:application.properties")
  @EntityScan("com.tomholmes.springboot.phonebook.server.domain")
  public class TestRepositoryContextConfiguration
  { ... }
  
  @RunWith(SpringJUnit4ClassRunner.class)
  @SpringBootTest(classes = TestRepositoryContextConfiguration.class)
  @ComponentScan("com.tomholmes.springboot.phonebook.server")
  @Transactional
  public class BaseDaoTests
  { ... no other code needed here ... }
  
  
  
  public class ContactDaoTest extends BaseDaoTests
  {
      @Autowired
      private ContactDao contactDao; // repository
  
      ... all tests here ...
   }
  </code></pre>
  
  <p>So, this took a lot of trial and error and I finally got it to run.  The tests which are using Spring Data all seems to work great!  So, I am happy here.</p>
  
  <p>The next layer is the springboot-phonebook-service module, which contains all the business services and business logic.  The pom.xml does contain a dependency to the springboot-phonebook-dao.jar.  The services should just call the DAO code that was compiled in the last module, and I don't know if that works.   The problem is that I cannot get the tests to run at this point.</p>
  
  <p>Here is the business code:</p>
  
  <pre><code>public interface ContactService
  {
      List&lt;ContactEntity&gt; getAllContacts();
      List&lt;ContactEntity&gt; getContactsByUserId(long userId);
      ContactEntity getContactById(long contactId);
      ContactEntity add(ContactEntity newContact);
      ContactEntity update(ContactEntity newContact);
      void remove(long contactId);
  }
  </code></pre>
  
  <p>And here is the implementation of that code:</p>
  
  <pre><code>@Transactional
  @Service("contactService")
  public class ContactServiceImpl implements ContactService
  {
      @Autowired
     private ContactDao contactDao;
  
     @Override
     public List&lt;ContactEntity&gt; getAllContacts()
     {
      List&lt;ContactEntity&gt; contactList = (List&lt;ContactEntity&gt;) contactDao.findAll();
      return contactList;
      }
  
       ... other code ...
  }
  </code></pre>
  
  <p>The test code is configured as such:</p>
  
  <pre><code> @SpringBootApplication
   @PropertySource(value = "classpath:application.properties")
   @EntityScan("com.tomholmes.springboot.phonebook.server.domain")
   public class TestServiceContextConfiguration
   { ... }
  
   @RunWith(SpringJUnit4ClassRunner.class)
   @SpringBootTest(classes = TestServiceContextConfiguration.class)
   @ComponentScan("com.tomholmes.springboot.phonebook.server")
   @Transactional
   public class BaseServiceImplTests
   { ... }
  
   public class ContactServiceImplTest extends BaseServiceImplTests
   {
        @Autowired
        private ContactService service;
  
      ... test cases ...
    }
  </code></pre>
  
  <p>And so now, I am getting an error that the Application Context cannot be loaded.</p>
  
  <pre><code>Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.tomholmes.springboot.phonebook.server.dao.ContactEmailDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
  </code></pre>
  
  <p>This bean:  com.tomholmes.springboot.phonebook.server.dao.ContactEmailDao
  is in the springboot-phonebook-dar.jar, and the source code is defined as:</p>
  
  <pre><code>@Repository("contactEmailDao")
  public interface ContactEmailDao extends CrudRepository&lt;ContactEmailEntity, Long&gt;
  {
  List&lt;ContactEmailEntity&gt; findByContact(ContactEntity contact);
  }
  </code></pre>
  
  <p>So, that is it ... it's taking a lot of trial and error, and I am just not getting a handle on how Spring Boot is put together. Once I clear this hurdle, the next step is to setup the last layer which is the web-services.</p>
  
  <p>The idea is that once these springboot-phonebook-service all test ok, then I will compile this into a springboot-phonebook-service.jar file.   </p>
  
  <p>The next layer, springboot-phonebook-ws will have a pom.xml that contains the springboot-phonebook-service.jar as a dependency.  This last layer should have the SpringBootApplication in it, and will compile to a WAR file.   This is the MAIN Application, and the rest of the jars are just dependencies for this WAR file module.</p>
  
  <p>That's it in a nutshell ... any help would be most appreciated!   Thanks!</p>