How to retrieve full endpoint URL in Quarkus test? - quarkus

I am looking a solution to retrieve full endpoint URLs within Quarkus application to use it in tests to avoid hard-coding the paths.
The official guide suggests using the #TestHTTPEndpoint and #TestHTTPResource annotations.
If I annotate my test class with #TestHTTPEndpoint(MyResource::class), then all calls via RestAssured without specifying the path work just fine. The problem is, when I try to retrieve the endpoint URL like this (let's say, I need to call multiple endpoints in one test):
#TestHTTPEndpoint(MyResource::class)
#TestHTTPResource
lateinit var myResourceUrl: URL
it kind of works, but the injected URL does not include the quarkus.http.root-path value.
Instead of http://localhost:8081/root-path/my-resource I get just http://localhost:8081/my-resource.
Is there a way to retrieve a full endpoint path that includes the quarkus.http.root-path value?

Introduction
Let's consider the following versions as the current versions.
Quarkus: 2.11.2.Final.
Root cause analysis
The io.quarkus.test.common.http.TestHTTPResourceManager (TestHTTPResourceManager for short) class performs the value injection into the fields annotated with the io.quarkus.test.common.http.TestHTTPEndpoint (TestHTTPEndpoint for short) annotation:
The TestHTTPResourceManager class retrieves an instance of the org.eclipse.microprofile.config.Config (Config for short) from the org.eclipse.microprofile.config.ConfigProvider (ConfigProvider for short) class and uses the test.url configuration property value retrieved from the Config instance (the Config.getValue(…) method call) as the base URL.
The retrieved test.url configuration property value seems to correspond to the test.url system property value that was provided by the io.quarkus.test.common.http.TestHTTPConfigSourceProvider (TestHTTPConfigSourceProvider for short) class.
Possible root cause
For some reason the TestHTTPConfigSourceProvider class does not take into account the quarkus.http.root-path property value, when providing the test.url system property value, which seems to be used as the base URL: quarkus/TestHTTPConfigSourceProvider.java at 2.11.2.Final · quarkusio/quarkus:
static final String TEST_URL_VALUE = "http://${quarkus.http.host:localhost}:${quarkus.http.test-port:8081}${quarkus.servlet.context-path:}";
static final String TEST_URL_KEY = "test.url";
Therefore, it looks like a Quarkus issue: a defect (a bug) or a lack of a feature (or a lack of the feature implementation).
Therefore, it is worth reporting it as a Quarkus issue.

OK, so it seems to be a bug in Quarkus and will be fixed soon.
#TestHTTPResource annotation injects endpoint URL without the quarkus.http.root-path segment · Issue #27416 · quarkusio/quarkus · GitHub.
As a workaround, one could set the quarkus.servlet.context-path property in the test/resources/application.properties file like this:
quarkus.servlet.context-path=${quarkus.http.root-path}

Related

Reading a configuration Value from YAML in Micronaut

How to read a value from application.yml in my Micronaut project? I can clearly see annotation is resolved to proper value (true in this case), but it is not applied to the variable (stays as default false). I've tried using #Value and #ConfigurationProperties
In a comment the OP has indicated that they are doing new FeatureToggleService(). Creating your own instance of the object is the problem. Instead of using new, let the DI container create and manage the instance. If you do, then #Value will be relevant.
See https://github.com/jeffbrown/filiard/blob/f6f704fb95d7821919748bb41968f87d11cee07b/src/main/java/filiard/DemoController.java and https://github.com/jeffbrown/filiard/blob/f6f704fb95d7821919748bb41968f87d11cee07b/src/main/java/filiard/FlagHelper.java for a working example.
UPDATE:
Based on additional information this is not the correct answer!!!
As pointed out, #Value can be private, but Micronaut advices against it.
Short answer, it is because it is private. Wrong
From the documentation:
The #Value annotation accepts a string that can have embedded placeholder values (the default value can be provided by specifying a
value after the colon : character). Also try to avoid setting the
member visibility to private, since this requires Micronaut Framework
to use reflection. Prefer to use protected.
Also, consider using #Property instead of #Value. Still valid
https://docs.micronaut.io/latest/guide/#valueAnnotation
NOTE:
The Micronaut framework does not inspect a manually created instance, even if it is instantiated in a #Factory, unlike other frameworks.

Quarkus - #ConfigMapping: built-in way to show all properties like "toString()", instead of manual building

As #ConfigMapping uses interfaces, there are no ways to implement toString(); I cannot view all values and nested values without a lot of manual work(reflection and switch case to deal with each type).
Any plan to support easy view of all levels of properties? Like a super class to inherit which handles this manual toString() like building?
In SmallRye config doc page I read this:
ToString#
If the config mapping contains a toString method declaration, the config mapping instance will include a proper implementation of the toString method.
But I added #Override String toString(); method everywhere, Quarkus just complains about cannot find property "to_string".
OK I found this issue which is implemented in this commit, which exactly adds the sentence I read into the doc; but still not very clear to me.
Adding a String toString() method in your #ConfigMapping will generate the expected toString() implementation.
This is only available starting from SmallRye Config 2.11.0 and Quarkus 2.12.0.Final, which came out just a few weeks ago. Previous versions will just try to resolve the method as a configuration property. From your description, it seems that is the case, so you may be using an older Quarkus version that does not support this feature yet.

Kotlin Spring boot #Value annotation process

#Value("\${datasource.host}")
private val host: String = ""
I wrote the following code in KOTLIN and it worked fine.
I don't understand how the host was injected into the host.
In my knowledge, the value should not be injected because the host variable is val.
How does this code work?
Short answer: Spring is magical!
For a Kotlin property, val doesn't necessarily mean that the property is constant.  (It's not an exact equivalent of Java final here.)  It simply means that there's a get() method but no set() method.
That leaves open the possibility for the value to change some other way.  (For example, the property could have a custom getter which returned different values.)
I'm not sure quite how Spring works its magic; it may be able to set the property's backing field directly, or it may create a hidden subclass which can.  In any case, it's perfectly capable of setting val properties.  (You can also see this in Hibernate.)

How to map service factory PIDs to their `ObjectClassDefinition`

In OSGi R6 I desire to programmatically validate user-supplied String configuration properties plus a service factory PID against what is supported by whatever configurable #Component (or ManagedServiceFactory) that declares it configures this PID, e.g. #Component(configurationPid=some.service.factory.pid, ...). Additionally, I want to somehow convert valid String properties to their appropriate property types. Looking through the OSGi Compendium, it seems the Metatype Service is what I'm looking for.
If that's correct, given the following:
Applicable components uses component property types to specify their configuration
Component property types are annotated with #ObjectClassDefinition
Components are annotated with #Designate, mapping it to the applicable #ObjectClassDefinition
Is this the most straightfoward way to map factory PIDs to their ObjectClassDefinition:
Call BundleContext.getBundles(). For each bundle, call MetaTypeService.getMetaTypeInformation(Bundle).
For each returned MetaTypeInformation call MetaTypeInformation.getFactoryPids() and filter on the factory PIDs I care about.
For applicable MetaTypeInformation, call MetaTypeInformation.getObjectClassDefinition(String, String) to obtain the ObjectClassDefinition, using either a default or specific locale.
(Tangential, the above seems expensive to perform each time, so caching bundle IDs, mapping them to associated factory PIDs, and keeping the cache up-to-date somehow seems appropriate.)
Or, is there some other OSGi magic that can be programmatically queried with a service factory PID, which returns something that gets to some ObjectClassDefinition quicker than the above process?
Update 1
Stepping back, I'm writing a CRUD-wrapper around ConfigurationAdmin for each of my configurable components. I'm trying to avoid createFoo, deleteFoo, updateFoo, createBar, ... My application happens to be amenable to URIs. So my working approach was to use Metatype Service, pass in a parsed URI query (Map<String, List<String>>), and then utilize Metatype Service to validate and reconstruct these values, circling back to the OP. (On the side, seems like a not-pretty hack to me.)
Another approach was to use aQute.bnd.annotations.metatype.Configurable.createConfigurable(Class, Map), which I preferred more! Until I saw this bnd GitHub comment:
The bnd metatype annotations are deprecated in bnd 3.2 and will be removed in bnd 4.0. These annotations are replaced by the OSGi metatype annotations.
So I didn't want to rely on that package if it's going away soon. I looked at what Felix does and didn't want to use their equivalent Configurable class. I'm all ears on different approaches!
Update 2
Reducing this more, I'd like to validate potentially user-supplied key/values configuration properties to ensure they're applicable for some configuration pid, prior to calling ConfigurationAdmin.createFactoryConfig. Maybe this is overkill?
I once created a class that takes the configuration class, creates a proxy, and then uses this proxy to get the name of the method and the type. It was used something like this:
ConfigHelper<Config> helper = new ConfigHelper( Config.class, "my.pid");
int port = helper.get().port(); // get the configuration
helper.set( helper.get().port(), 1000);
helper.update();
The proxy you get from the get would record the method when one of the methods is called. On the set method it would use the last called proxy method to identify the property. It would then convert the given value to the property type based on the method's return value. The bnd converter is ideal for this but I think Felix now has a standard OSGi converter. (Which is based on the ideas of the bnd converter.)
The method name is then used as the property. The name mangling necessary is defined in an OSGi spec. This allows you to use underscores, Java keywords, and dotted names.
So this would allow you to roundtrip configurations. No worry about the types, they will automatically fall in their place.
Updated This is updated after I understood the question better
Updated 2 Added an example at https://github.com/aQute-os/biz.aQute.osgi.util/tree/master/biz.aQute.osgi.configuration.util

Default handler mapping for annotation based spring project

I am new to spring framework. Even I dont have any deep concept about annotation.
I am developing a very small application using spring mvc 3 framework and also I used annotation.
I have a confusion. I have one spring-servlet.xml. Here I have not defined any handler mapping. But still it is working. So must be there some default handler mapping. Can you please let me what is this default handler mapping and how I can override it so that I do some customization.
It is all explained in: http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config
Also see this question: How to use default-servlet-handler and Where to put default-servlet-handler in Spring MVC configuration
Spring 3.1 and later doesnt need DefaultAnnotationHandlerMapping and AnnotationMethodHandlerAdapter declaration in the [servelt-name]-servlet.xml
These links might help:
Spring Controller to handle all requests not matched by other Controllers
https://dzone.com/articles/using-the-spring-requestmapping-annotation
I had the same problem that I just resolved so I have confirmed the approach below works, although this is with annotations rather than an XML configuration.
You specify URL prefixes at the controller class level and include a request mapping annotation for ** to ensure you match on anything that falls through your other handlers for this class. There's really nothing special or default about this handler other than the fact that you're defining a handler that is guaranteed to match everything under the class level mappings.
Note: This is not magic. Your handlers are still subject to Spring's ordering algorithm regarding the "best match". It would be nice to have an annotation providing for a true default when nothing else matches handler, especially in cases with complex mappings where "**" is useful outside of this catch-all handler. The basic implementation is:
#RestController
#RequestMapping(value={"/path1/","/path2/"})
public class MyRestController {
#RequestMapping("/subpath")
String matchedRequestHandler () {
return "This matches /path1/subpath and /path2/subpath.";
}
#RequestMapping("**")
String unmatchedRequestsHandler () {
return "This matches everything else.";
}
}
In my actual use case, I needed to handle arbitrary paths to resources inside of the URL pattern and therefore needed to support a variable number of directories. Ideally, that would be handled using a pattern such as:
"/base/{optionaldir}/**/{entityName}/{describeVar:describe.json}"
which works fine by itself, but it isn't compatible with a default handler bound to "**" since the "**" mapping is calculated by Spring as a better match for these types of requests.
Instead, I had to add a bunch of separate entries to my request mapping to support the arbitrary paths within the URL pattern, e.g.
value={"/base/{optionaldir}/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/{entityName}/{describeVar:describe.json}",
"/base/{optionaldir}/*/*/*/{entityName}/{describeVar:describe.json}"
}
Alternatively, I could have handled everything with a "**" mapping and parsed the URL myself, but that kind of defeats the purpose of using request mappings with path variables. Hopefully Spring's capabilities will evolve in this area in the future.

Resources