Spring JPA multi module project - spring

I am trying to create a Spring multi module project.
Module 1, handles the application startup and basic web MVC services.
Module 2, is for MultiTentanted Jpa
Module 2, runs fines fine as stand alone application, but when I include it as a dependency in module 1, I get the following error, Caused by: org.springframework.data.mapping.MappingException: Couldn't find PersistentEntity for type class uk.rteksoft.tenantservices.tenant.model.Role!
I am assuming that I am missing something in a configuration bean somewhere, but haven't been able to find out what I need to do to make this work.
I have a parent pom that contains both module 1 and module 2.
Please say if I need to post any configs or other files.
Thanks
John

You need to scan base package from injected module else spring will not create any bean for injected module and you will face dependency errors.
Use scanBasePackages value in SpringBootApplication annotation in main application (you can scan array of packages based on your requirement)
ex:
#SpringBootApplication(scanBasePackages = "com.example.multimodule")
Here is example link of sample app based on multiple
ComponentScan is another way to scan multimodule packages;
#ComponentScan(value = "com.example.multimodule")
also Use below annotations for scan your entities and repositories
#EntityScan("your entity base packages")
#EnableJpaRepositories("your repositories base packages")

Related

Autowire a Bean from dependent library jar

I have a Spring Boot application (main-app) which users Library jar client-app.jar and mentioned as a dependency in of the application main-app.
Now I want to use #Autowire to inject bean from client-app. For this i have to add #ComponentScan on my main-app application.
But is there a way that i don't have to anything on my main-app by changing code on client-app.
Yes, you can create a sub-package by following the main-app let's say main-app has the following root of package com.example.main-app then on your client-app you should create something like com.example.main-app.client-app then the main application will scan its base package and will look the client-app as well.

Refering bean from one jar to another

I have 2 jars, common.jar and business.jar. common.jar contains common functioanlilty shared across all modules and most important it has hibernate session factory configuration like -
.
Now, I want to refer mySessionFactory from common.jar to my business.jar because I am defining transaction information in my business.jar and transaction configuration needs HibernateSession info.
Please suggest me how to refer bean from one jar to another.
Regarding the code dependency itself (making the business module depend on the commons module for source code reuse purposes), I suggest you use a build tool (maven or gradle would be good candidates).
Regarding DI, you should define a configuration in the commons module (I suppose you already have this if Hibernate works fine in the commons module).
#Configuration
// other configurations for Hibernate, component scans, etc
public class CommonsConfig {
}
Then, in the business module, you should import the commons configuration.
#Configuration
#Import(CommonsConfig.class)
public class BusinessConfig{
}
Now the beans from the commons module should be detected by the component scan from business module (and you should be able to use #Autowire for beans from the commons module in the business module).

Spring AOP aspect doesn't get applied if included from an external jar with different package name

I have a spring boot rest service that included an external project in pom as it's dependency. That external project is basically a jar that has spring AOP code.
The base package in my main application that includes this external jar with spring AOP code is x.y.z
The class in external jar where the #before advice is, is under the package a.b.c
With this class under a.b.c package, it doesn't get recognized by the main application where I want to use the spring aop implementation and apply the aspect. However, when I change it's package from a.b.c to x.y.z (which I really can't do in real life) it works fine.
I know that in spring boot service which happens to be the including service, it scans everything under root package given in the application class, x.y.z in this case and that is why aspect works fine if it's class is under x.y.z.
however, the problem is that this spring app jar will be used across multiple applications. So changing package name like this is not an option.
Is there a way to accomplish this without changing the package name of the class where spring app code is ?
Probably component scan is only activated for your application class packages by default. You can extend it to multiple packages, including the aspect package:
XML style configuration:
<context:component-scan base-package="x.y.z, a.b.c" />
Annotation style configuration:
#ComponentScan(basePackages = {"x.y.z", "a.b.c"})
Disclaimer: I am not a Spring user, only an AspectJ expert. I just knew that you can configure component scan, googled the syntax for you and hope it is correct.
Please define the bean (of jar project )inside main application. Give the #ComponentScan(basePackages = {"x.y.z", "a.b.c"}) as well as #EnableAspectJAutoProxy. Also include below piece of code.
ex:
` #Bean
public LoggingHandler loggingHandler()
{
return new LoggingHandler();
}`
Also annotate external jar code with:
`#Aspect
#Component
public class LoggingHandler {`
What #kriegaex suggests is correct. In addition to that, please make sure you are using #Component along with #Aspect. Since #Aspect is not a Spring annotation, Spring won't recognize it and hence your aspect won't be registered. So, using #Component is mandatory to getting aspects to work in Spring environment.

Wiring a bean from dependency module

I have created a configuration project which essentially creates couple of beans with configuration stereotype. Then, I want this project to be reused across by my clients.
I have added this config project as a maven dependency, but my client project is not having those beans i have created as part of configuration project.
Could someone help
Ok, the answer is the following: you should place
#ComponentScan("you.configurations.base.package")
on one of your configuration (in the current application, one that #SpringBootApplication sees) or on the class with #SpringBootApplication annotation.
The explanation is as follows: #SpringBootApplication under the hood contains #ComponentScan without specifying a base package. That means that it says to Spring to scan the package where the class annotated with #SpringBootApplication resides and all the packages recursively. And that's it. If you place you #Configuration somewhere there - it will create it during startup, otherwise not.
We can resolve this by enabling spring-boot autoconfiguration
Create classpath->resources->META-INF->spring.factories file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=[add your class with you need to be loaded during application load time]

Bootstrap a Spring #Configuration class from another Maven module in a multi-module project

Before the spiel, I think the question essentially boils down to this:
How can I instantiate correctly #Configuration beans from an application's XML-based configuration?
In an attempt to modularize my project and follow something of a clean architecture, I have created a Maven project composed of three modules. There is a "web" module an "interface" module and a "core" module and both web and core use Spring's Java-based configuration.
The web module declares in it's POM a runtime dependency on the core module and a compile-time dependency on the interface module. The core module is the implementation of the interface module, the latter being composed of only Java interfaces and DTOs. (This is an attempt to program to interface modules.)
When I start the web module I want all the Spring-managed beans from the core module to become known to the web module's application context. I've had some success doing this the "XML-way" by creating an XML file in the core module that looks like this:
// This xml snippet is part of the "core" module
<beans>
<context:annotation-config />
<context:component-scan base-package="com.acme.core"/>
</beans>
... and referencing this in the web module configuration like so:
// The configuration of the "web" module
#Configuration
#ImportResource("classpath*:come/acme/configuration/spring/*.xml")
public class RootConfig {}
It works but I'm not happy with the solution because I want all the configuration for the core module to be done the Java way.
So to that end, I note that Spring says one can do the following:
...#Configuration classes may be declared as normal definitions within Spring XML files:
<beans>
<context:annotation-config/>
<bean class="com.acme.configuration.spring.CoreConfig"/>
</beans>
That would be (almost) ideal if it worked because the XML file in the core module would be very lean and essentially just bootstrapping the meaty configuration in CoreConfig. However it doesn't work for me and the web module cannot find any of the beans that are defined in the core module. I think this might be because if the beans are instantiated then they are done so in a different application context or maybe because CoreConfig, being marked with #Configuration, is special and instantiating it this way from the XML file doesn't trigger the creation of the other beans it defines.
Incidentally, I'd rather have a way to do this without any XML configuration but referencing com.acme.configuration.spring.AppConfig directly from the web module is not possible since there is no compile time dependency on the code. (Sigh) Modularizing is so far proving to be more trouble than it's worth...
The following works when specified in the config class of the "Web" module in my example:
#Configuration
#ComponentScan(basePackages={"com.acme.configuration"})
public class RootConfig {}
In fact, it is what #M. Deinum said to do in a comment on the question. In this example, all com.acme.configuration packages, regardless of whether they might be in another Maven module, will be picked up and processed correctly. It is necessary then, by convention, that all configuration classes of other modules be placed in com.acme.configuration. With this approach there is no need for any XML configuration file to "bootstrap" the configuration as I was trying to do.

Resources