Guice Dependency Injection between different projects - java

Initially I started working on a Play! Java project that has a Controller, Processor and DAO. I used dependency injection using Google Guice's #ImplementedBy for my Processor interface and my ProcessorImpl implemented it.
Right now, I have created another project which also requires the Processor. So I extracted out the interface to another separate project, say common, and the two projects use that common project as a referenced library.
The problem is, I won't be able to use #ImplementedBy anymore since that common project will not have the two projects' references. Since that is not possible, I am not able to go for dependency injection. Without giving #ImplementedBy, I am getting the following error:
play.api.UnexpectedException: Unexpected exception[ProvisionException: Unable to provision, see the following errors:
1) No implementation for com.processor.Processor was bound.
Is there a way to configure the dependencies in a config file? Or can the dependency be injected in the implemented classes?

Create a guice module in project where your ProcessorImpl is located.
public class Module extends AbstractModule {
protected void configure() {
bind(Processor.class).to(ProcessorImpl.class);
}
}
Inject Processor wherever you need.
If you call this module Module and place it in the root package, it will automatically be registered with Play.

Related

Annotation processing does not work with lombok and java

I am working on my own multi modules project, where I am using lombok.
The problem occured when i wanted to start the application, and terminal showed error:
java: Annotation processing is not supported for module cycles. Please ensure that all modules from cycle [domain,service] are excluded from annotation processing
So I turned off the annotation processing in project settings
And there are no more errors with modules annotation processing, but there is the new error.
My classes which use lombok does not recognize builder method
java: cannot find symbol symbol: method builder() because lombok require annotation processing - even intellij shows message: Do you want to enable lombok annotations? when I turn on intellij.
Is there any way to solve this?
Okay, I solved this problem with help of #xerx593 user.
The main reason why it was not working was this part of error:
modules from cycle [domain,service] which means that there was a module cycle in my project.
I have got three modules: domain, service and ui where
service module is contingent on domain module and
ui module is contingent on service
so the structure looks like this: domain -> service -> ui:
my pom.xml in ui module should implement service module dependency
my pom.xml in service module should implement domain module dependency
and pom.xml in domain module should not implement any of ui and service dependency
but because of my fault, I implemented service dependency in domain pom.xml and there was the problem with module cycle dmoain -> service -> domain
After i deleted this service dependency in domain module, everything works!
From the error message, I conclude:
There is a (dependency) cycle in your modules:
domain and
service
Unfortunately the error message doesn't recommend you to elliminate these cycles, but (rather gently and task focused) only to "exclude them from pre-processing" (which is of course needed by lombok et.al.)
To proof yet (when you google "java module cycles", then you hit only this problem on the top results ..whereas "java module cycles good or bad?" brought me here:
Why are cyclic imports considered so evil?
), but I think "cyclic modules" is a "anti-module-pattern", and as long your "system" ist small and over-viewable: Break these cycles & avoid them!
So in your case, I would avoid any imports from service to domain
so depend only unidirectional! service -> domain ..., and not domain -> service!
, which will re-enable your pre-proccessing & lombok.
the question itself may need a little bit more context, but in the meantime, looking at lombok's setup for IDEA might help you https://projectlombok.org/setup/intellij. TLDR when working with lombok on IDEA you can use this extension to have hints without rebuilding the whole project (since annotation processing kicks in when running the compiler).

How to add runtime dependency on another module?

I am writing an extension for a library which consists of several Maven modules. I need to add some functionality on top of one module but do not want to add unnecessary dependencies in case somebody wants to use this module without my extension (typical use case).
One solution that I can think of is to create another module with my extension and try to call methods from its classes using reflection. There would be some kind of check like this:
try {
Class.forName("my.package.Foo", false, getClass().getClassLoader());
// extension will be enabled and some method will be called using reflection
} catch(ClassNotFoundException e) {
// extension will be disabled
}
And methods on that class will only be called if it is on classpath. The extension can then be activated if you add Maven dependency on its module (in addition to the dependency on the module it extends).
But this does not sound like the best approach. Are there any more elegant solutions to this problem?
The one way is to use built-in Service provider interface (SPI).
The basic idea is to make your optional libraries to provide an implementations of some interface (a "services") which may be easily found by your main application. Take a look at this example
// scan classpath for all registered
// implementations of Module interface
ServiceLoader<Module> loader = ServiceLoader.load(Module.class);
for (Module module : loader) {
module.doSomething();
}
Once your optional dependency is in classpath service loader will find it.
You can find a lot of examples in "Creating Extensible Applications" tutorial from Oracle on how to make it.
The other way is to use dependency injection frameworks such as spring or google guice. These frameworks are also providing a classpath scanning mechanisms for automatic component discovery. This solution is a way more flexible but heavier than SPI.
you can definite your dependency like this:
<dependency>
<groupId>com.thoughtworks.paranamer</groupId>
<artifactId>paranamer</artifactId>
<version>2.6</version>
<optional>true</optional>
</dependency>
checkout the detail from this link
Simplest would be to create a new Module as you mentioned. And in this new Project A you have a dependency to this existing Module that you are talking about Project B.
So now any body who wants to use without your extension would use Project B. And anyone who would need your extension would use Project A.
Just make sure to add the Maven dependencies in the build Path to avoid ClassNotFound conflicts.

Is it possible to create a JAR with an aspect that is automatically applied to classes in client project?

I want to have a JAR with an aspect that intercepts all method calls, e.g.
#Aspect
public class CoolAspect {
#Pointcut("execution(public * *(..))")
public void anyPublicMethod() { }
#Before("anyPublicMethod()")
public void advice(JoinPoint point) {
System.out.println("sign:\t" + point.getSignature());
}
}
Suppose the above is the aspect I have and want clients to use. I compile it to a JAR and make available to Maven.
Now the clients would use this jar as a dependency, e.g.
<dependency>
<groupId>cool-group</groupId>
<artifactId>cool-artifact</artifactId>
<version>1.0.0</version>
</dependency>
This artifact (JAR) has the mentioned aspect.
Now is it possible for the aspect work by just declaring a Maven dependency?
Few things that might be important:
I plan to use AspectJ (perhaps Spring AOP, if necessary),
The clients will probably be web applications with normal web.xml etc.
Clients are built with Maven
I want the Clients to be as easy to configure as possible - in my original idea a Maven dependency would be enough.
The "Annotation JAR" will contain a web-fragment, so it's possible to declare some custom ServletContextListener there..
Any ideas?
Find a simple solustion for this question if you are using spring-boot:
In the jar, you can define your aspect as a component:
package com.xxx.yy.zz.aspect;
#Aspect
#Component
public class CoolAspect {
// code like the question
}
And the, you need create a file spring.factories in /resources/META-INF/.
Spring will scan this file when start.
And the file spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.xxx.yy.zz.aspect.CoolAspect
After that, just package them as a jar.
This will work by just declaring a Maven dependency
No, this is impossible, because AspectJ must be started prior to any client classes. All client classes should be loaded through a special enhanced class loader, which will process annotations.
The other thing is Spring's AOP. it weaves beans during application context start up and does not require special class loader. That would be the easiest way for client if he uses spring. Add maven dependency and then configure AOP in the application context.
There are four types of weaving:
Compile-time weaving is the simplest approach. When you have the
source code for an application, ajc will compile from source and
produce woven class files as output. The invocation of the weaver is
integral to the ajc compilation process. The aspects themselves may
be in source or binary form. If the aspects are required for the
affected classes to compile, then you must weave at compile-time.
Aspects are required, e.g., when they add members to a class and
other classes being compiled reference the added members.
Post-compile weaving (also sometimes called binary weaving) is used
to weave existing class files and JAR files. As with compile-time
weaving, the aspects used for weaving may be in source or binary
form, and may themselves be woven by aspects.
Load-time weaving (LTW) is simply binary weaving defered until the
point that a class loader loads a class file and defines the class to
the JVM. To support this, one or more "weaving class loaders", either
provided explicitly by the run-time environment or enabled through a
"weaving agent" are required.
Run-time weaving, this is what actually Spring is doing. We
define this as the weaving of classes that have already been defined.
to the JVM

maven - separate modules for interfaces and implementation with Spring

We are working on Mavenizing our java project and we would like to setup a clean separation between interfaces and implementations for each module.
In order to do so, we want to split each module into two sub-modules one for interfaces and data objects used by them and another for implementations.
For example:
+commons
+commons-api
+commons-impl
The POMs of the modules will be configured such that no module depends on the impl sub-modules. This way no code from one module will be able to "see" implementation details of another module.
What we are having trouble with, is where to put our spring XMLs.
In our project we automatically import spring XML files using wildcard import like
<import resource="classpath*:**/*-beans.xml"/>
This way the location of Spring XMLs doesn't really matter at runtime, as all the modules get loaded into the same class loader and, the strict one way dependency rules in the POMs don't apply.
However, during development we want the IDE - we use Intellij IDEA - to recognize implementation classes referenced from the spring XMLs.
We also want IDEA to recognize beans defined in other modules.
If we put the spring XMLs in API sub-modules - they won't "see" the implementation classes in the impl sub-modules.
If we put them in the impl sub-modules, their beans won't be "seen" from other modules.
It is probably possible to configure the IDEA project to recognize spring XMLs from modules on which there is no dependency, but we prefer for our POMs to hold all the project structure information and not rely on IDEA project files.
We considered creating a third sub-module just to hold Spring XMLs (and perhaps hibernate xmls as well). For example:
+commons
+commons-api
+commons-impl
+commons-config
The external modules will depend on both commons-api and commons-config and commons-config will depend on both commons-api and commons-impl, with the dependency on commons-impl marked as "provided" (to prevent transitive resolution).
This however seems like a complex and awkward solution and we feel that there must be a better - simpler way to achieve interface/impl separation with Maven and Spring.
What you need is a runtime dependency scope:
runtime - This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
(https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
Define a runtime dependency from one impl module to another impl module where you use the impl classes in the *-beans.xml config. Intellij will correctly recognize this in spring configuration files, but won't auto complete them in code (but it will do that in test code).
Also if anyone used the classes in the code, compilation through maven would fail, because the runtime dependency is not on a compile class path.
You can achieve decoupling of api and impl like this:
+ commons (pom)
+ pom.xml <--- serves as a parent aggregator (see below)
+ commons-api (jar) <--- contains models, interfaces and abstract classes only
+ commons-impl (jar) <--- depends on commons-api
+ commons-config (jar) <--- depends on commons-impl only (no need to depend on commons-api as it is brought in transitively)
+ external-project (war or jar) <--- has commons-config as a dependency
Parent aggregator pom (specify build order):
<modules>
<module>commons-api</module>
<module>commons-impl</module>
<module>commons-config</module>
</modules>
The config module can be omitted if it only contains spring application context configuration. The app configuration xml should be in the classpath and folder structure of the module that contains the artifact that you are deploying. So if you are building a war artifact, the app context should be in there.
The only configuration that should be in your commons module would be in a test package of your impl module.
In short you want Idea to override maven dependency graph but avoid keeping this configuration in idea project files?
One option is to group implementation dependencies in a maven profile. This profile would not be enabled by default but you should be able to mark it as active under idea.
Two ideas come to mind:
You will have one (or more) modules where all the modules (api+impl) are dependencies, you could place your spring configuration files there.
Place the spring configuration files in the api modules and declare a dependency on the impl module with scope provided this way the implementations will be known, while there is no dependency of the api for the deployment.
commons-impl at runtime scope in external modules
commons (pom dependencyManagement) =>
+commons-api (compile)
+commons-impl (compile)
+commons-config (compile)
commons-impl (pom dependencies) =>
+commons-api (compile)
+commons-config (compile)
external modules (pom dependencies) =>
+commons-impl (runtime)
+commons-api (compile)
+commons-config (compile)
keep modules number as little as possible;
This speeds up project build time and simplifies its layout.
keep modules structure as plain as possible: single root + all sub modules in the same folder, e. g.:
pom.xml
commons-api/
commons-runtime/
module-a-api/
module-a-runtime/
...
This simplifies navigation across the project, when modules number is really high (>50)
provide runtime-scoped dependencies to the runtime modules only when they are required;
This keeps your architecture clear. Use mocks instead of explicit dependency to another runtime module.
keep your api spring contexts in api modules, define your public beans as abstract bean + interface;
keep your implementation contexts in runtime modules, override api beans with your implementations via spring profiles (use <beans profile="default").
Result: simple, transparent layout and design; full ide support; no explicit dependencies on runtime module internals.

Referencing an interface's implementation from another maven module

I have a maven module "dd.core" containing an interface say CoreService, which is implemented in another maven module "dd.another" as CoreServiceImpl.
Now when I am trying to refer the CoreService in my core module "dd.core" as
#Autowired
#Qualifier(value="coreService")
CoreService coreService;
I am getting bean creation exception,
I have added in my "dd.core" module
How can i resolve this issue ?
Thanks a lot !
Since your interface is implemented in another module, you cannot use that implementation in dd.core. If you need an implementation for some test in dd.core, you can use a mock instead (or write a test implementation). If you need an implementation in yet another module, you need to depend on dd.core and dd.another in that module. If you need something else, please elaborate.
What you cannot do, however, is add a dependency on dd.another in dd.core, otherwise you're introducing a circular dependency.
Check that your dependencies are correctly defined.
Does your /dd/another/pom.xml include a dependency to the dd.core artifact?

Categories

Resources