Quarkus Extension - Remove a class from dependent library or replace part of a class - quarkus

Within a custom Quarkus extension I would like to integrate an existing java library that currently is not compatible to Quarkus.
Are there any examples for the following use cases:
remove a java class from a dependency library (library is referenced as maven-dependency)- In this case I'll provide a compatible implementation within the runtime-module.
replace specific parts of an existing class form a dependency library (e.g. a default implementation of an interface)
Thanks, Thomas

For the first case, you can use a io.quarkus.deployment.builditem.RemovedResourceBuildItem to have Quarkus essentially remove a class from a dependency.
For the second case, you'll likely need to use a io.quarkus.deployment.builditem.BytecodeTransformerBuildItem which lets you declare an ASM class transformer which can change a class in arbitrary ways.
If you are only looking to change the class for native mode, it's much easier to instead use com.oracle.svm.core.annotate.TargetClass and com.oracle.svm.core.annotate.Substitute.

Related

How to split code in library for spring boot starter

Imagine that I have a library A, that provide a given functionality that can be enabled like a spring-boot-starter, meaning that adding the dependency to my project will make it available.
On the other end I have another library B, that provide another functionality, similar to library A in the way it works, but it is a totally different feature.
Now I have a case where if the project include libraries A and B I would like to configure some bean in a specific way.
My question is how to decide where to do write the code needed both libraries, clearly it should either be:
library A having optional dependency on B with a specific #Configuration that enable that bean
the opposite, library B having optional dependency on A with a specific #Configuration that enable that bean
On purpose I leave the name A and B to be as generic as possible in my case, one library is applying some specific configuration for mongo and the other one is to wrap the mongock migration tool.
You could do the following:
Write your libraries A and B without Spring Boot in mind (no beans, no dependency injection etc.)
Declare both libraries as dependencies (Maven/Gradle) in your project
Define a #Configuration class that defines all the beans that you need, similar to this
Decide with Spring profiles and #Qualifier which been you need when
I wrote a blogpost about how you can use #Profile to decide for different Spring Beans based on the given scenario: https://medium.com/twodigits/keep-your-code-debuggable-4ad69e5e0ac7

How do I include components, scanned from a Spring library, into the main application consuming that library?

We are building a Spring-based Java library that has several #Autowired assignments, which pick up #Bean instances from the library path, detected at runtime.
That works great when we test the application directly (with an #SpringBootApplication in the library)
However when we include the library as a dependency in other projects, it does not do the component scan of the library classes, and so the #Autowired injections never happen.
Of course we could tell the application developers to add the library path to their component scan, but that would lead to questions, errors, and frustration.
How can we tell Spring to do a component scan of the library classes, without explicitly including the scan base in the consumer applications?
You could create a configuration in your library which defines the components the library needs. This answer shows something like that.
Another way would be to create your own autoconfiguration. This article in the spring documentation describes how it is working.

How to use Spring to back Freemarker "?new" built in?

Currently we have a number of classes that extend TemplateMethodModelEx which we construct using Spring and then inject into the Freemarker Configuration as shared variables so they are available as functions to all of our templates.
However, it would be nicer to have more fine grained control and make these methods available on demand in individual templates. One can instantiate them using the ?new built in, but internally that uses the general Java reflection mechanism for instantiating the class, and these models need to be constructed via Spring to get their dependencies.
In a perfect world, I'd like to make it so that the ?new built in use Spring to construct the class. It looks like to do that I would need to find a way to overload BeansWrapper.newInstance(Class, List) to use Spring, but I'm unclear on the best way to accomplish that.
Note that we are currently using Freemarker 2.3.23

Why do people cite the ability to "define module boundaries" as an advantage of OSGI?

Don't the default Java access modifiers (public, protected, private) already define boundaries for how classes can be accessed. Why are these modifiers not sufficient? Why is OSGI's way of "defining moudle boundaries" better than this?
Yes, the java access modifier's define a classes boundaries and to some extent a package's boundaries but a module is larger than a single class or package. You may want to see http://www.slideshare.net/bjhargrave/why-osgi which explains the progression of encapsulation through classes and onto modules.
Short answer
In a modularized system it is very important to separate API from implementation where only API is exported. You cannot do that based on class modifiers. Other very important part of OSGi is the versioning of packages. You have to assign version only to those packages that are exported.
Long answer
A more prcise answer to this question is available at the following wiki post that was written by Neil Bartlett: http://wiki.osgi.org/wiki/Export_Only_APIs
Similar question
Why do we need object-orientation when functions are already available in structured languages? Are not the functions used to separate logical units of an algorithm?
I thought about it a little bit, and realized that there are certain privacy restrictions that OSGI's export mechanism can impose that plain old Java access modifiers cannot. See the diagrams below.
Notice how in Plain Old Java, a public class is visible (indicated by a green arrow) to all classes no matter what. In OSGI, a public class is visible to all classes (including classes in another bundle) ONLY if it is part of an exported package.
Note:The "protected classes" in the diagram are really just classes without any modifier (since there is no "protected" modifier for classes, just for fields and methods)
Edit: I'm adding this relevant quote from here: http://njbartlett.name/files/osgibook_preview_20091217.pdf
"A public class is visible to every class in every other package; a default access
class is only available to other classes within the same package.
There is something missing here. The above access modifiers relate to visibility
across packages, but the unit of deployment in Java is not a package, it is a
JAR file. Most JAR files offering non-trivial APIs contain more than one
package (HttpClient has eight), and generally the classes within the JAR need
to have access to the classes in other packages of the same JAR. Unfortunately
that means we must make most of our classes public, because that is the only
access modifier which makes classes visible across package boundaries.
As a consequence, all those classes declared public are accessible to clients
outside the JAR as well. Therefore the whole JAR is effectively public API,
even the parts that we would prefer to keep hidden. This is another symptom
of the lack of any runtime representation for JAR files."

Is it possible to obtain the classes or methods of other class with out adding a reference of that class

In my project i am having 2 class libraries namely DAL and BAL . While adding reference only one reference is added and for the other i am getting some Circular Dependancy error. So is there any possibility to obtain the members of other class with out adding reference of that class.
A circular dependency usually means there is a design flaw in your system. If there is some common functionality that both libraries need then perhaps extract that into a third assembly and reference that from both.
Alternatively, you could have a third project that references the other two and is responsible for handling communication between them, a mediator.

Resources