I split up my projects into multi-module projects often and heavily.
How can I declare in the Maven 3 POM that "Some implementation of API xy has to be available in the package".
For example, if I split my services layer in a services-api and services-impl and declare in the API that the deployable has to have a dependency on an implementation of services-api, even if its not the services-impl module itself.
Is this possible?
If you need an implementation of an API, then something has to choose which impl. If you don't care which, you have then 2 choices:
Either you just choose an impl and declare it in the POM, using <scope>runtime</scope>, which excludes the impl at compile time, but it will be made available to the container.
Or you use or implement a Service Provider Interface (SPI)
To quote from the Oracle tutorial (emphasis added):
A set of programming interfaces and classes that provide access to some specific application functionality or feature. The service can define the interfaces for the functionality and a way to retrieve an implementation.
Related
I have an interface A with a method Result doAction(Param param). I have a Spring application that will use implementations of the interface and call doAction() on it.
But the application does not define an implementation itself. The idea is that other people can provide their own implementations of the interface in JARs (plugins), the main application will pull those in as dependencies, and call doAction() on the JAR's implementation.
Any idea how I can do this in practice? The ideas I had were:
Try to autowire the implementation through Spring Boot, but for that I would need to know its package and add it to the component scan. So it would mean putting requirements on the naming of the "plugin" jar. Something I would prefer not to do.
With plain Java my first idea was to keep a registry of implementations (e.g. a Set<Interface A>), but the plugin wouldn't be able to access the registry -- it would be a dependency cycle.
What I'm doing right now is defining a Rest API that the "plugin" needs to implement, deploy the plugin in the same environment and the main application just makes the calls through the Rest API.
But for performance reasons I'm looking for a solution with more direct calls that doesn't involve communication over the network. Any suggestions?
When migrating to Gradle 7, we have to replace the compile configuration by the implementation or api configurations.
According to the Gradle documentation:
An API dependency is one that contains at least one type that is exposed in the library binary interface, often referred to as its ABI (Application Binary Interface). This includes, but is not limited to:
types used in super classes or interfaces
types used in public method parameters, including generic parameter types (where public is something that is visible to compilers. I.e. , public, protected and package private members in the Java world)
types used in public fields
public annotation types
When migrating large code base with lot of dependencies, it is a tedious task to determine for each dependency if it's an implementation or an api dependency.
My question is: How to determine automatically if a dependency should be an api or an implementation configuration ?
To automate it, you would need to effectively incorporate the tests from your consumers, assuming there are tests, into the tests of the project. In other words, publish the module locally, modify the consuming project to use the updated dependency, and run their tests. Or write a tests in your project that uses your consumers code would be another approach.
For example, Gradle tests Gradle against select community plugins to ensure they don't break anything: https://github.com/gradle/gradle/tree/master/subprojects/smoke-test/src/smokeTest/groovy/org/gradle/smoketests
However, then the questions becomes: who is consuming my project? That itself can be a tedious task.
If you are unsure or don't want to take the time to determine api or implementation, then use api since it is more or less the "same" as compile.
I'm doing a project with modules in android, and within each module I have sub-packages with their respective entities, repositories, etc. To handle access within this packages, I must use public class, and this gives access to other modules. I need a single class/packages to be used as an API that can be Access from other modules and hides internal implementation.
I'dont know if java allow this? how i can do this?
thanks
Access from other modules and hides internal implementation
Yep. Extract the API to an interface and then define an implementation of that interface with a visibility modifier lower than that of the public interface. Hide the binding of that interface-to-concrete implementation via an init method of your module. Expose this init method to your module too.
Using dependency injection or a service locator pattern, you can then request the implementation of this interface from your caller modules. Generally, in more complex applications, it's dependency injection you're wanting to use. In this case, a factory method is required to bind between the interface and concrete implementation.
If you are using a dependency injection library with Java then you're likely looking at using an #Binding and an #Provides method to achieve this wiring and provisioning respectively.
I'm trying to get my head around some concepts in Java:
JSR(s): describe specifications, but carry no actual implementations. E.g. http://jsr311.java.net/ is the "home" for "Java™ API for RESTful Web Services". It serves as a common reference for all implementations of JSR-311.
One can download the interfaces (?) of JSR-311 from http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, however, unless you are implementing JSR-311 by yourself these have no particular value?
JSR(s) will usually/always have a reference implementation. To find it you'll have to google "JSR XXX reference implementation" or see the specifications home page (e.g. http://jsr311.java.net/)
For JSR-311 this reference implementation is Jersey. Using maven you can get the jersey server from http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9. Since
Jersey provides an implementation according to the interfaces found in http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, you only need to add Jersey as a dependency in your project and not the jsr311-api itself. (this applies to all JSR technologies?)
Putting both http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api and http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9 as dependencies in your project will possibly cause classpath problems?
Am I completely off or onto someting?
Yes, this isn't anything new. Think about JDBC, java provides the
interfaces (Connection, Statement, ResultSet etc) but it is up
to database vendors to provide implementations.
If you're using a JSR-311 implementation like Jersey or Apache CXF
then you'll annotate your classes with the javax.ws.rs annotations, such as #Path, #GET, #Produces etc. This is why you need to explicitly have JSR-311 as a maven dependency.
Yes, usually. Have a look at the JSR list on wiki.
You need both the JSR and the implementation. The annotations are in the JSR, the implementation provides supporting classes, such as com.sun.jersey.spi.container.servlet.ServletContainer.
No, it is necessary to have both as dependencies (see point 4); you won't get classpath conflicts.
—
One can download files from a variety of sources. To get the most official version of the JSR-311 specification go to its JCP download page. It's quite possible that you can't get a JAR file (with all the interfaces and stuff) from JCP pages, but still, this is the official source. (There are always nice PDFs of public drafts also!)
—
You're right, because Jersey contains the API defined by JSR-311, however I would add a compile dependency to the jsr311-api JAR file and add Jersey as runtime dependency. This creates a nice separation between API and implementation and you can swap out your JSR-311 implementation anytime [sic]. If you intend to use Jersey all the way include only Jersey. One less dependency in your POM.
If Jersey packages the same API as the jsr311-api JAR contains, it won't. If it packages something different, well, that would be awful! Maven will probably bark at compile time if one has a corrupt JSR-311 API on its classpath (I've already seen lots of java.lang.ClassFormatError: Absent Code attribute in method that ... errors, so it won't go unnoticed, that's for sure).
Other than these, you're right.
SLF4J has a nice mechanism, where the implementation is chosen at runtime, depending of what is available in the classpath. I would like to use such feature in several projects, for example to choose the communication layer or to choose a mock implementation.
I had a look at slf4j source to see how it's done and I could just write something similar. Before I start, I would like to know if some lightweight FOSS library exists for this kind of injection.
Unless you need specific configuration abilities as provided by Pico or Guice, you may get what you need from java.util.ServiceLoader.
Basically, all you have to do is to package your service implementation in a JAR file, include a text file with a list of all implementation classes in "META-INF/services/" and on you go.
Have you looked at Weld, CDI is part of the EE6 spec but the Weld implementation also supports running in a Java SE environment. It has exactly what you are looking for, here is a link to the relative documentation:
http://seamframework.org/Weld one maven dependency for your SE app.
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/environments.html#d0e5333 bootstrapping the Weld container in SE.
Producer methods to vary implementation at runtime:
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/producermethods.html
Plus (in my very biased opinion) Weld rocks ;)
SLF4J's "mechanism" is simply that its API jar is compiled with code that refers to a class that is only provided by one of its "implementation" jars. No framework or library of any kind is needed for this. Simply write one module which is compiled against a class not in that module. Then your "implementation" modules provide that class when included in the project.
Edit: Oh, and this is basically OSGi writ small (very, very small). If you're going to use this kind of thing on a large scale, look to an OSGi container or Eclipse Virgo.
Every java programmer should know how to use Spring.