we have a kotlin-microservice that needs to expose a maven-artifact that defines all DataTransferObjects that are required/emitted by that microservice (e.g. kotlin data-classes that represent events published to the event-bus).
client of that microservice is however a pure java application which shall depend on this kotlin-DTO-maven-artifact but not transitively get the kotlin-stdlib or any other kotlin-specific dependencies injected.
can we provide the kotlin-DTOs without introducing any kotlin-dependency?
The easiest and the most reasonable for me would be to create those DTOs as Java classes since the Kotlin is compatible with such classes
You don't need for this any additional tools or tricks. Inside this artifact you can easily use Lombok to not write plenty of boiler plate code
Related
I am currently building a spring boot application with a micro-service architecture.
I am looking for clean ways to reuse code.
My idea is to pull out common code in a shared module.
(e.g. base classes which model classes in microservices inherit from, interfaces which are reused in any mvc controller, domain code which is the same for each bound context).
Concrete implementations and service-only model classes etc. are on the submodule (microservice) level.
I am building stuff with maven and also managing dependencies. My question is about how to structure maven modules and dependencies in such a setup.
Where do shared libraries go? How and when are they built and referenced via dependency?
Is it good to use a BOM for managing dependencies and only override specific versions in microservices when needed?
How is the bom included? How and when is it built?
I can think about one way to handle it which I don't really like:
Have a (super-parent) maven pom which handles dependency management and can be included in submodules (micro-services) with import scope. (BOM)
microservices poms build all their dependencies (including BOM and shared module)
Problems:
when declaring submodules for building dependencies the pom must be of type pom aswell, so for every microservice module I would also need a parent pom aswell
If the super-parent or BOM includes a module section which declares all submodules (microservices) I cannot build it from the ms-level, since there would be circular dependencies.
Why would I even declare submodules in the bom? because in some IDEs like Intellij the maven plugin/support includes the submodules in the structure overview.
Can you please point me to some good advice for handling maven architecture for microservices in a solid and clean way? (less code/configuration duplication as possible, performant build etc.)
Thanks
The first thing you should concern about with the microservices architecture is the isolation of the services from each other. That implies that you should share as little as possible.
As I tried different approaches over past 6-7 years I can confidently say
Don't ever use a parent pom for different microservices. Each microservice can use different version of the same libraries depending our their own needs. Having parent pom may sound convenient initially but it creates significant issues in the long run for isolation.
Don't ever try to focus on code reuse between the microservices. That doesn't mean that you can't use utility libraries etc. But sharing model classes etc. will bind the microservices to each other which will damage the freedom/isolation substantially. Instead you should rely on proper contract between the microservices.
I see that your approach are mostly for implementation convenience but there are other things you should concern more over time like deployment/release, maintenance, testing of the components which could be harmed by lack of proper isolation.
I want to reuse and centralize the utils I created for my Spring REST API for my future projects. That's why I thought I'd outsource them to my own project and make them available as a Maven dependency.
These Util files e.g. a basic service, basic controllers also contain Spring annotations, i.e. I need some Spring dependencies in my Util dependency. Now I'm a bit unsure whether I'm making a mistake or not.
First of all, I'm not sure if I should even use spring dependencies in a utility dependency or try to remove everything. Otherwise, I'll have to specify a spring version, but it might differ from the version I want to use later in the project it's included in. How am I supposed to solve this?
It is perfectly reasonable to have dependencies for your dependencies (these are called transitive dependencies). Of course, you should keep the number as low as possible, but on the other hand, you do not want to reinvent the wheel.
When somebody uses your dependency, they will automatically draw the transitive dependency on spring. Now, several cases can occur:
If this is the only reference to spring, the version is just used as you stated it.
If at some other point, a different version of spring is given, Maven dependency mediation kicks in. It decides by a "nearest is best" rule which version to take.
But: You can always set the spring version in <dependencyManagement> and then overwrite all transitively given version numbers.
That is the main concept of Maven. Your utility module must shipped together with Spring dependencies. It's called transitive dependencies.
Try to imagine that situation when all dependencies had excluded. In that case nobody will never know what kind and which version of Spring dependencies are needed.
Maven has a very good dependency conflict resolution. It's based on nearest-newest principle. So you can override those Spring versions easily and your application will use only one of that.
Take a look at these:
[1] Dependency Mechanism
[2] Dependency Mediation and Conflict Resolution
I have submodule rest that defines couple of dependencies with implementation. And I have another module app that uses implementation project(":rest").
However the dependencies of the rest declared with implementation are not available for app. I know implementation does that by design, but how to make them available without using original compile configuration?
It seems I need to use plugin java-library and use api configuration for that dependency.
I am developing a simple web application, using Spring Framework.
When I add Spring framework to my class path, I see that it has lot of jars which I never use (for example: spring-aop-3.2.3.RELEASE.jar).
Is it a good idea to keep the entire framework intact or remove unused jars?
If you need to remove unused jars, the best way is to use some dependency management tool like Ivy or Maven, and let the tool decide what the required dependencies are. Otherwise it will not be apparent what is really unused or not until you break something.
For instance, if you are using declarative transactions, then removing the AOP jar will cause breakage, because AOP is used to implement that functionality.
If you would rather not use dependency management, it's better to leave everything intact.
There are some cases where you do want to remove/exclude jars. Replacing commons-logging with slf4j is one example. Another example is excluding the log4j dependencies that get dragged in on account of some appender that's packaged with log4j but that you know you will never use. Dependency management tools allow you to tell them what needs to be excluded.
Doing without dependency management management and removing things because you never use them directly is too dangerous.
Is it not possible to include dependencies based on class properties? E.g. if I am building a framework that I want to integrate with any customer system, the type of DB the customer uses could be a variable but my framework may use it if it can acquire a data source. So in this case, my Maven project should be able to integrate with any DB by declaring the corresponding DB war as dependency.
E.g.
<dependency>
<artifactId>${database.artifactId}</artifactId>
....
</dependency>
But this database.artifactId in itself will be read from properties file that may be accesible to customer code, so the idea of having parent pom declare the versions and artifactId as mentioned here may not suit my case.
Is there a work around or is this use case itself so wrong? I strongly think if we build a framework that is more like a product the customer can integrate with, this flexibility of declaring any runtime dependency based on propertie should be there.
Thanks,
Paddy
This is not how it is done with Maven.
If, as in your case, you write a framework that may use different dependencies, then you do not somehow conditionally depend on the concrete implementation. This would not work, as the exact list of dependencies is constructed at build time (i.e. when the Maven artifact of you framework is built and installed).
Rather, there should be a special Maven artifact which describes just the interface of the functionality that you need. This artifact will typically contain the (Java) interfaces your framework needs; this is what your framework will depend on.
Then, when using your framework, a concrete implementation of these interfaces must be included - by the people using your framework, because only they know which implementation they use.
This is explained for example in "Maven by Example", chapter "7.10.1. Programming to Interface Projects".
Example:
JDBC: The interface is part of the JDK, so a framework that uses JDBC does not need to declare any special dependencies (if JDBC were not part of the JDK, you would depend on a Maven artifact like "jdbc-api" or similar). A software that actually uses JDBC will have to depend on whatever JDBC driver it actually uses (Oracle, HSQL etc.).