I am new in quarkus and have a question regarding dependency injection with quarkus.
I am on a project to migrate an application to quarkus. The old application uses spring and runs on JBoss. My goal is to migrate it to quarkus. For several weeks now, I have faced a problem concerning dependence injections. The old application uses an external xml file for the configuration of these beans (like their scope ...). There is therefore no annotation in the bean classes apart from #Named on each bean. My current problem is that I cannot modify certain dependencies to add annotations (such as #Requestscoped, #ApplicationScoped ...) so that I can inject them into my classes because they are external dependencies.
Does quarkus have a way to add annotations to beans without modifying the class where these beans were defined ?
Thanks.
Expected behavior :
Being able to inject beans that only have the #Named annotation into my code.
Actual behavior :
Beans are not injected because they have no #RequestScoped, #Dependent... annotation
quarkus version : 1.5.1.FINAL
Output of java -version :
openjdk version "1.8.0_252"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_252-b09)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.252-b09, mixed mode)
Output of mvn --version :
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: C:\MAVEN\apache-maven-3.6.3\bin..
Java version: 1.8.0_252, vendor: AdoptOpenJDK, runtime: C:\Program Files\AdoptOpenJDK\jdk-8.0.252.09-hotspot\jre
Default locale: en_IE, platform encoding: Cp1252
OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
There is no config property or so. However, you can write a Quarkus extension that leverages build-time APIs to transform the annotations of your classes, possibly based on the external file configuration.
Related
I'm trying to create a GraalVM native image using the maven plugin but having some issues.
Here the config for the maven plugin
I'm using GraalVM JDK (installed through Sdkman):
$ java -version
openjdk version "16.0.1" 2021-04-20
OpenJDK Runtime Environment GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05)
OpenJDK 64-Bit Server VM GraalVM CE 21.1.0 (build 16.0.1+9-jvmci-21.1-b05, mixed mode, sharing)
I have a done simple main class like:
package it.r;
public class Main {
public static void main(String[] args) {
System.out.println("********");
System.out.println(Main.class.getConstructors().length);
System.out.println("********");
}
}
When executing it using mvn exec:java -Dexec.mainClass=it.r.Main I get as a result:
********
1
********
But when doing mvn package and then executing the created executable, I have as result:
********
0
********
Why is this happening?
Here the git repo to reproduce
This issue seems to impact Jackson deserialization, as in another example I have an error from jackson that cannot deserialize a yaml file because it can't find constructors for my class.
When GraalVM native image builds your application into a native binary it statically analyzes your application.
The analysis is static, so several dynamic features your application might use require explicit configuration, for example:
reflection
serialization
method handles
using resources (like classloader.getResource())
JNI
This explicit configuration is provided as json configuration files, for example,
You can provide the config files manually, but you can also run your application using a javaagent which will record usages of features requiring configuration.
In a nutshell, you run your application like this:
java -agentlib:native-image-agent=config-output-dir=/path/to/config-dir/
and exercise the code paths that use the code you want to be configured. This is important because the tracing agent can only record the config for the code it actually saw running.
Then the output directory will contain a json file, for example looking like this:
[
{
"name":"StringCapitalizer",
"methods":[{"name":"capitalize","parameterTypes":["java.lang.String"] }]
},
{
"name":"StringReverser",
"methods":[{"name":"reverse","parameterTypes":["java.lang.String"] }]
}
This file lists the classes that need to be included into the analysis and the binary result and their members that need to be accessed.
It’s fairly straightforward but a bit tedious to create manually that’s why the agent approach is preferred.
There’s also a programmatic way to configure classes and members be registered for reflection, but using it means you need to include a dependency on the GraalVM code into your app.
Classes using reflections need to be registered in order to include them in the native image built, more info in the docs
Latest version of STS (e.g. 3.7.3) does not support Grails anymore so I'm using STS Gradle projects as workaround in order to run my Grails applications with "Spring Boot App" option. It's working just fine, but I have faced the issue below:
Issue:
Somehow all the beans declared under resources.groovy file have been ignored when I execute the application via STS running as "Spring Boot App". Notice that running the application via console "run-app" command it works fine.
Exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'facebookAuthRedirectFilter': Cannot resolve reference to bean 'redirectFailureHandlerExample' while setting bean property 'authenticationFailureHandler'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'redirectFailureHandlerExample' is defined
My resources.groovy file
package spring
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
beans = {
redirectFailureHandlerFacebook(SimpleUrlAuthenticationFailureHandler) {
setDefaultFailureUrl('/login/auth')
}
}
STS:
Version: 3.7.3.RELEASE
Build Id: 201602250940
Platform: Eclipse Mars.2 (4.5.2)
Grails:
Grails Version: 3.1.1
Groovy Version: 2.4.5
JVM Version: 1.7.0_75
It seems classpath issue but I could not find how to resolve this yet.
Issue resolved by updating Groovy compiler settings. Go to Window->Preferences->Groovy->Compiler, see below:
Doing this resources.groovy will be compiled and the beans will be available on run time.
When trying to start a project (./grailsw run-app) for the first time with the latest version of the database-migration plugin, it fails with the following error:
Error Compilation error: startup failed:
[..]/work/plugins/database-migration-1.3.8/src/groovy/grails/plugin/databasemigration/GormDatabaseSnapshotGenerator.groovy: 48: You cannot create an instance from the abstract class 'liquibase.snapshot.DatabaseSnapshot'.
# line 48, column 31.
DatabaseSnapshot snapshot = new DatabaseSnapshot(db, requestedSchema)
I'm using java7 on OSX:
$ java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)
This seems vaguely familiar to me; I was able to find random references to other projects in 2009-2011 about this. Nothing current; and nothing found in the specific plugin's issue tracker. I'd ask there but I expect this is a fairly standard issue, not related to the specific grails plugin.
A peer is using java6. I went back to java6 (apple(tm) version), ran ./gradlew --refresh-dependencies run-app and got the same thing.
Looks like liquibase made that class abstract in v3
However, the plugin looks like it should be using v2.0.5
So as far as I can see, for v2.0.5 it should be ok?
Unless you've added a dependency to liquibase v3?
I'm developing with Grails 2.1.1 and now I want to integrate Logback (http://logback.qos.ch) as the default logging framework as it should provide some better logging features and could be also configured via Groovy.
As Logback 1.0.7 (latest) does only work with slf4j 1.6.6 I want to upgrade the Grails dependeny. Grails 2.1.1 is using slf4j 1.6.2. How to do this properly?
I tried the following: in BuildConfig.groovy I exclude grails-plugin-log4j and slf4j-api
grails.project.dependency.resolution = {
// inherit Grails' default dependencies
inherits("global") {
excludes "grails-plugin-log4j", "slf4j-api"
}
...
}
and I try to load slf4j-api 1.6.6 in compile build and runtime along with the other necessary libraries
grails.project.dependency.resolution = {
...
dependencies {
// specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes eg.
compile "org.slf4j:slf4j-api:1.6.6"
build "org.slf4j:slf4j-api:1.6.6",
"ch.qos.logback:logback-core:1.0.7",
"ch.qos.logback:logback-classic:1.0.7"
runtime "org.slf4j:slf4j-api:1.6.6",
"org.slf4j:log4j-over-slf4j:1.6.6", // logback dependency for classic module, as seen on http://logback.qos.ch/dependencies.html
"ch.qos.logback:logback-core:1.0.7",
"ch.qos.logback:logback-classic:1.0.7"
}
...
}
now, if I want to do anything from the Grails commandline, either grails compile or grails clean, it's complaining that it couldn't execute the script because it couldn't find the LoggerFactory class:
| Loading Grails 2.1.1
| Configuring classpath
| Error Error executing script Compile: org/slf4j/LoggerFactory (NOTE: Stack trace has been filtered. Use --verbose to see entire trace.)
java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:156)
at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:272)
at org.springframework.core.io.support.PathMatchingResourcePatternResolver.<clinit>(PathMatchingResourcePatternResolver.java:169)
| Error Error executing script Compile: org/slf4j/LoggerFactory
How can I upgrade the underlying slf4j-api properly?
If I don't exclude the slf4j-api first, I get a conflict with the "old" 1.6.2 api marked as evicted when calling grails dependency-report...
Also, I'd love to have an external config file for Logback. How would I implement it? With Log4j I just declared a log4jConfigurer bean within the conf/spring/resources.groovy file - how would it be done with Logback?
Has anybody experience in logging Grails 2.1.1 with Logback and could give me any advice for this issue?
As I think that this question would be also a matter of fact for other developers willing to implement the Logback Logging Framework with Grails, I'll share my progress on the topic within this answer - trying not to overload the initial question with progress information.
I still had no luck in updating slf4j within Grails, so I stuck
with the solution to simply overload the slf4j-api dependency.
Grails would show no error on grails dependency-report, just an
"eviction notice" on the older slf4j dependency (1.6.2). This seems
to work but I'll keep on searching for a better solution on this
topic.
I'm now able to load an external config file for Logback through
a ServletContextListener and a ConfigLoader class
implemented in grails-app/src/java, with the
ServletContextListener registered within the web.xml file. (to
get the web.xml simply execute grails install-templates on the
commandline. You'll find it under
grails-app/src/templates/war/web.xml) Be sure to make it the first
<listener/> entry within your web.xml so that Logback gets
configured and loaded as soon as possible.
I found this solution along with the full code sample over at
https://bowerstudios.com/node/896 which was the best and shortest
example I found on this topic which seems to work!
This solution just loaded the external configuration file and used
it within the ConfigLoader class but didn't set it for the whole
Grails application. So I googled around a bit more and I found a
solution from Logback, available at GitHub (https://github.com/qos-ch/logback-extensions) and integrating with the
Spring Framework, so I took these classes from this page and
the LogbackConfigurer class from here and tweaked them to fit
my needs.
Now everything works like a charm and I'am able to create an external configuration file and - what I like best - it's hooking in
with the log object which is injected to e.g. Controller classes
by default.
Hope this is also a help for other developers too ;)
If you've got a better or more "groovy" solution for this, pleas let me know!
I created an .eba file (enterprise bundle archive) that contains one osgi bundle having a apache camel route (Java DSL). The camel context definition is done via a blueprint xml file. When I tried to deploy the .eba file in Websphere Application Server 8.5, I got the following exception:
org.apache.aries.application.modelling.ModellerException: CWSAL0126E: An exception occurred while modelling bundle ib-base_0.0.1.SNAPSHOT: org.apache.aries.application.modelling.ModellerException: org.osgi.service.blueprint.container.ComponentDefinitionException: Unsupported node namespace: http://camel.apache.org/schema/blueprint.
My blueprint xml file is as follows:
<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/blueprint"
xsi:schemaLocation="
http://www.osgi.org/xmlns/blueprint/v1.0.0
http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
http://camel.apache.org/schema/blueprint http://camel.apache.org/schema/blueprint/camel-
blueprint.xsd">
<camel:camelContext id="cbrContext" trace="false">
<camel:packageScan>
<camel:package>a.b.c.d</camel:package>
</camel:packageScan>
</camel:camelContext>
</blueprint>
I am not too sure why this fails in Websphere. The same .eba file gets successfully deployed in Karaf 3.0.0-SNAPSHOT. (This version of Karaf uses Aries Blueprint version 1.0.0).
I guess the same is used or a forked version of the Aries Blueprint 1.0.0 is used in Websphere 8.5.
As per the OSGi specs, any blueprint extension handlers for custom namespaces like camel: are retrieved from the OSGi Service Registry under the key (osgi.service.blueprint.namespace). The value element tells the actual namespace uri .
eg:
<service interface="org.apache.aries.blueprint.NamespaceHandler">
<service-properties>
<entry key="osgi.service.blueprint.namespace" value="http://camel.apache.org/schema/blueprint"/>
<entry key="osgi.service.blueprint.namespace" value="http://camel.apache.org/schema/blueprint/cxf"/>
</service-properties>
<bean class="org.apache.camel.blueprint.handler.CamelNamespaceHandler">
</bean>
</service>
I am not too sure why IBM does not honor this spec.
Another interesting point to ponder over is the fact that when I tried to create a blueprint .xml file using Websphere Application Developer Tool, it shows only 4 extensions as shown below:
IBM Blueprint Extension
JPA Blueprint Support
Blueprint Transaction Support
Blueprint Resource Reference support
I ensured that both the camel-core and camel-blueprint bundles are deployed in the internal repository in websphere.
I tried to deploy the .eba file as an asset.
Not too sure, if I have missed something. I would be glad if someone can point me in the right direction.
best regards,
Sriraman.
WebSphere does not support custom namespace extension (other than the one provided by IBM). The main reason being it runs on Aries (Blueprint container) isolated runtime. There are two options
Use camel api instead of blueprint tags
Use other container (for e.g. Karaf) which supports custom namespace extension
Karaf is a friendly container for camel.