Add maven dependency conditional on another - java

I have several projects that depend on a common framework, built on top of Spring Boot. This framework autoconfigures lots of the things that applications use via BeanPostProcessor and similar Spring mechanisms.
It also adds support for optional libraries that the applications can use, using #Conditional beans and optional Maven dependencies.
The problem I'm facing is that one of those optional libraries is Resilience4J and I'd like to add a dependency on resilience4j-micrometer if Resilience4j is added, so I can expose out-of-the-box all Resilience4J metrics via Micrometer.
Is there any mechanism in Maven that allows to add a conditional dependency given some condition, so I ensure that every application using Resilience4J exposes its metrics?
PS: I tried to just create a module to wrap the dependencies, but there are different Resilience4J dependencies the applications use (some apps are web and others Webflux, some use the Spring Cloud abstraction and others don't...).

You can try to manage dependencies via maven profile but it not really the best way. Your framework should integrate all libraries and your app manage dependencies with exclusions in order that Spring Boot can autoconfigure only included dependencies.

I'm not sure I'm following your question, I assume that you have a library "common".
So you have an application A (spring boot driven), and in its pom.xml you add a dependency on "common". You would like to create Beans in the application context of A if A has a dependency on Resilience4J. These beans are supposed to add expose some micrometer related stuff.
In this case you could probably use ConditionalOnClass:
In "common"'s code you could have something like this:
#Configuration
#ConditionalOnClass(Resilience4j.class) // or whatever class that can indicate that resilience4j is in the classpath, I took this for the sake of example, I don't know whether this class really exists
public class CommonConfiguration {
#Bean
public YourMicrometerIntegrationBean yourMicrometerIntegrationBean() {
return new YourMicrometerIntegrationBean();
}
.. other beans ..
}
This solution assumes that you have a dependency (optional ?) at the level of maven in "commons" to resilience4j. If you don't want this for some reason, you could create your custom condition (I believe you know how to do that based on the details that you've supplied in the question you have a pretty advanced setup, let me know if you need more details on that), and this custom condition will evaluate to "true" if Class.forName(<FULLY_QUALIFIED_NAME_OF_RESILIENCE_4_J>) won't throw an exception so that you'll see that its available in runtime.

Related

Spring initialiser dependencies for a REST consumer console application

I am a Spring Boot newbie. I'd like to initialise a project which consists of:
A console application that acts on command line arguments so the JAR files could be later used in scheduled tasks.
Consumes a RESTful service
Logging
Which package dependencies should I choose in Spring Initializer? Apart from the necessary packages, are there any libraries that are optional but make development easier?
Depends on how you want to consume the restful service, but you may not need any extra starters, the core spring-boot-starter that you get when you just hit "Generate Project" and is usually implied with all the common starters like -web, -security, .. has logging and dependency injection and is all you need to create a jar that can easily be started with java -jar
However, it does not come with RestTemplate which is a common way to build rest clients in spring. For that you'll need to manually add a dependency on org.springframework:spring-web like you can see examples for in https://spring.io/guides/gs/consuming-rest/
But you can as well use other rest client libraries if you like them better.
There is also Feign that can be used as rest client and it's available from the initializer, examples at https://cloud.spring.io/spring-cloud-netflix/multi/multi_spring-cloud-feign.html - have not tried it and I'm not sure how much extra cloud dependencies will be added when you add the starter.
I also like having Lombok in all projects but that's preference. The obvious sounding choice of DevTools doesn't give you much benefit in a console application but is great for live reloading of web servers.
[...] so the JAR files could be later used in scheduled tasks.
sounds like you're trying to create a library / module of a larger application. You don't need an application that works standalone for that though so maybe https://spring.io/guides/gs/multi-module/ is good to read for you. Difference for libraries is that you don't need the spring boot plugin for maven/gradle which can package a standalone jar, just the dependency management.

When do we need a spring configuration in a multi module maven project?

I have set up my project in multiple modules based on the Spring framework. Currently there is only one runnable application combining all those modules.
Some of the modules provide functionality that might be reusable by other projects (or at least I could imagine reusing them in an other project). Some (but not all) modules also provide s spring Configuration. However when trying to create an application based on that configuration alone, requires defining many beans on top. This suggests that the configuration at that level does not make much sense, as there are dependencies on the level of Maven, which are not reflected in the Spring configuration.
As I am moving toward Spring Boot does this set up make sense or should the beans be defined at the level, where the configuration dependencies and Maven dependencies do match?

Should I use the Spring Framework jar files or Spring Batch jar files while creating a java email batch program?

I am trying to create a java email batch program that sends an email with an attachment each day to a specific email address, and I have to use Spring as the framework for this program. It is not going to be a web application, but since I'm implementing Spring into this, how would I go about this? I am totally new to Spring (and Java for that matter), but am unsure of which direction I need to go. Which jar files do I need? Spring Batch or Spring Framework? Also, where can I download the jar files for Spring Framework? The spring.io site won't let me download those jar files.
I very strongly suggest you use a build tool that handles dependency management. Such tools are Ant+Ivy, Maven and Gradle. They will take care of downloading the appropriate jars based on your declaration of what dependencies you need and will take care of all the transitive dependencies.
One good way of getting started with Spring Batch is to follow this tutorial using either Maven or Gradle (the latter would probably be easier since you don't need to install it - the tutorial's code has a wrapper).
The tutorial uses Spring Boot which vastly simplifies Spring configuration (which is a serious benefit especially for someone who is new to Spring)
As others already told you, I personally would not start any spring based project (means: any project) without maven! You have so much benefits from it, not only depencency management.
To start a spring app outside an application context:
#Configuration
public class AppConfig {
//any bean configurations here
}
//your entry class
static void main(String args[]) {
//get a reference to the spring context. use this context throughout your app!
ApplicationContext ctx = new AnnotationConfigApplicationContext(CacheConfig.class).get();
//optain any beans from the context. inside these beans, you can use any spring feature you like, eg #Autowired
ctx.getBean(YourBean.class).executeMethod();
}
I'd recommend starting with Spring Boot which will handle all of that for you. As others have mentioned, pick a build tool (Maven or Gradle) and follow the guide we provide on building a batch application here: http://spring.io/guides/gs/batch-processing/.

How to refactor a codebase that uses spring autowiring

I've inherited two fairly non-trivial codebases that uses spring for configuring the applications. Now I need to reconfigure the applications. But lots of the configuration is provided through autowiring so it is almost impossible to find out what the actual configuration is.
The projects are moderately sized, some 20-ish maven modules per project including integration test modules and such. Most modules define a few application contexts for various purposes, that contain one or two local spring config files along with one or two from the core modules it depends on. The result is a myriad of configurations, and that I cannot alter a class or variable name (or setter method) without risking breaking dependencies in some upstream or downstream module, even if no such dependency is visible anywhere in the project.
How do I work effectively with autowired dependencies in spring?
Can anyone, perhaps someone who actually likes autowiring, provide some insight into how you work with them effectively?
(I also inherited a small project that combines xml-files, autowiring and annotation-driven config, making dependency relations completely intractable, but I'll save those annotations for a separate question later)
You can perform re-factoring of auto wired beans using Intellij (I have version 9 Ultimate). Also Intellij has an option of making autowiring dependencies explicit. Link Provided below
http://blogs.jetbrains.com/idea/2009/03/making-spring-autowired-dependencies-explicit/
What IDE are you using? Spring STS (an Eclipse based IDE) has a lot of tools for working with Spring annotations and autowiring as well as good set of refactoring tools.

Can Spring understand #Inject replacing Weld as a JSR-299 implementation?

I have noticed from several web pages that apparently Spring 3.0 supports #Inject from JSR-330. As we would really like to use JSR-299 syntax for dependency injection in our libraries for both web apps and stand-alone applications, and have alternatives to Weld, it would be nice if Spring could do this.
Being a novice to Spring, I tried downloading the Spring Framework distribution and put all jars on the Eclipse build path. No Inject annotation so my existing test project using Weld did not compile.
Can this be done with Spring? What do I need to do to get it running?
(I am aware that Guice eventually will support this too. It is only in SVN for now, and if there is an official Spring release which can, that would be better.)
It can be done. The JSR-330 jar must be downloaded seperately, and cglib to parse the manually written #Configuration classes, plus a commons logging implementation.
The largest difference from Weld seems to be that the wiring needs to be manually written instead of magically found (a bit more cumbersome, but may make more robust applications), plus the startup time is much less. I am still new to Spring - is there a way to have #Configuration classes autodiscovered?
From the Spring 3.0.x Reference documentation:
JSR 330's #Inject annotation can be used in place of Spring's #Autowired in the examples below. #Inject does not have a required property unlike Spring's #Autowire annotation which has a required property to indicate if the value being injected is optional. This behavior is enabled automatically if you have the JSR 330 JAR on the classpath.
So you can make your code agnostic of the DI framework by using #Inject, but you still need to include a jar with the javax.inject classes in your project because Spring does not ship them itself. You can find the relevant jar in the downloads section at JSR-330's Google Code site.
The javax.inject package is not included as part of Spring 3, but it does support it if it's present.
If you look at the source for AutowiredAnnotationBeanPostProcessor, you'll see the constructor uses reflection to locate javax.inject.Inject, and logs a message if it finds it. There's no compile-time dependency on it.
You'll need to locate the JSR-330 JARs from some other source (e.g. the JavaEE 6 SDK).

Categories

Resources