Our company creates an ejb in two artifacts. The impl artifact contains the implementations and the client artifact contains all the interfaces. This means that the impl artifact has a compile dependency on the client artifact.
Now at runtime, the client artifact needs the impl artifact - otherwise the container cannot inject the required objects. This means that an ear needs to contain the impl artifacts for all client artifacts.
Does this mean that the client artifact should have a runtime
dependency on the impl artifact? Or should these "circular" dependencies be avoided, even if one direction is compile
and the other is runtime
?
Does this mean that the client artifact should have a runtime dependency on the impl artifact?
No and there is no dependency (or better should not be). Take a look at the import statements in the client artifact's classes and interfaces and you will see that the client artifact does not depend on implementations.
If the client would depend on the implementation it would violate the dependency inversion principle which is part of the SOLID principles.
Or should these "circular" dependencies be avoided, even if one direction is compile and the other is runtime?
In fact at runtime an implementation is needed, but that is a question of component assembly. One might want to replace the implementation some day or for test reasons. So it wouldn't be a good idea to introduce a maven dependency in the client artifact to the implementation only to make component assembly a little bit easier.
Instead you should declare the implementation dependency in the EAR deployment unit, because the EAR is the assembly of the enterprise application.
EDIT
Our developers complain that making sure that every client has a corresponding impl in the ear is tedious manual work. One looks for all client artifacts in the dependency:list, adds all corresponding impl artifacts, calls dependency:list again, adds again all missing impl artifacts etc.
I think they take the JEE development roles description word by word.
A software developer performs the following tasks to deliver an EAR file containing the Java EE application:
Assembles EJB JAR and WAR files created in the previous phases into a Java EE application (EAR) file
Specifies the deployment descriptor for the Java EE application (optional)
Verifies that the contents of the EAR file are well formed and comply with the Java EE specification
Nevertheless the specification also says
The assembler or deployer can edit the deployment descriptor directly or can use tools that correctly add XML tags according to interactive selections.
I would say that the a ear
pom is an example of an assembly description using a tool.
JF Meier also mentioned
Some developers write scripts for this process, but then again, after one changes versions of some ejbs, one needs to repeat the process because maybe somewhere deep down in the dependency tree, ejb-clients were erased or added, so additional impls might be necessary.
To me these scripts are the same as the ear
pom. Maybe more flexible, but at the price of standards and conventions. The fact that they have to update the scripts with every release makes clear that it would be better if these versions are also updated by maven.
Furthermore... Since the ear pom is just a maven artifact, it can be deployed to a repository as well. This is better then private scripts that noone except the author has access to.
I hope these arguments will help you when discussing the deployment strategy with your colleagues.
You do not need to be concerned with the client's implicit dependency upon the implementation because the server will manage that.
The EJB container creates a proxy through which the implementation is invoked, so there is never a direct reference to it from the client.
If you have the pom for the EJB containing:
<groupId>com.stackoverflow</groupId>
<artifactId>Q43120825-server</artifactId>
<packaging>ejb</packaging>
<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
</dependency>
<dependency>
<groupId>com.stackoverflow</groupId>
<artifactId>Q43120825-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-ejb-plugin</artifactId>
<configuration>
<ejbVersion>3.2</ejbVersion>
</configuration>
</plugin>
</plugins>
</build>
and the EAR file pom containing:
<dependencies>
<dependency>
<groupId>com.stackoverflow</groupId>
<artifactId>Q43120825-server</artifactId>
<version>1.0-SNAPSHOT</version>
<type>ejb</type>
</dependency>
<dependency>
... other modules
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<artifactId>maven-ear-plugin</artifactId>
<version>2.10.1</version>
<configuration>
<version>7</version>
<defaultLibBundleDir>lib</defaultLibBundleDir>
<modules>
<ejbModule>
<groupId>com.stackoverflow</groupId>
<artifactId>Q43120825-server</artifactId>
<bundleFileName>Q43120825-server.jar</bundleFileName>
</ejbModule>
... other modules that might have the API jar as a dependency
</modules>
</configuration>
</plugin>
</plugins>
</build>
then this will build a correct EAR file with the API jar in it's lib
directory.